2

組み込みオブジェクトを C# のインターフェイスにキャストする方法を定義することは可能ですか? インターフェイスは演算子を定義できません。インデックスへのアクセスは許可するがミューテーションは許可しない非常に単純なインターフェイスがあります。

public interface ILookup<K, V>
{
    V this[K key] { get; }
}

Dictionary<K, V>aを anにキャストできるようにしたいと思いILookup<K, V>ます。私の理想的な夢の世界では、これは次のようになります。

//INVALID C#
public interface ILookup<K, V>
{
    static implicit operator ILookup<K, V>(Dictionary<K, V> dict)
    {
         //Mystery voodoo like code. Basically asserting "this is how dict
         //implements ILookup
    }
    V this[K key] { get; }
}

回避策として私が取り組んだのはこれです:

public class LookupWrapper<K, V> : ILookup<K, V>
{
    private LookupWrapper() { }

    public static implicit operator LookupWrapper<K, V>(Dictionary<K, V> dict)
    {
        return new LookupWrapper<K, V> { dict = dict };
    }

    private IDictionary<K, V> dict;
    public V this[K key] { get { return dict[key]; } }
}

これは機能し、Dictionary から ILookup に直接キャストできるようになったことを意味しますが、複雑に感じます...

インターフェイスへの変換を強制するより良い方法はありますか?

4

5 に答える 5

2

インターフェイスには実際のコードを含めることができないため、キャスト用のコードを「ホスト」するクラスが必要になります。これは、(明らかに)インターフェイスを実装するクラスにするか、そうでなければ、あなたが持っているようなラッパークラスにする必要があります¹。3 番目のオプションはありません。

¹キャストを「呼び出す」方法は異なる場合があります (たとえばLookupWrapper、拡張メソッドの後ろに a の構築を隠すことができます) が、これは状況を変えません。

于 2011-12-15T01:14:49.247 に答える
0

ディクショナリを制御できる場合は、ディクショナリをサブクラス化して、サブクラスでオーバーライドできthis[]ます。次に、.NET辞書の代わりに新しい辞書を使用します。

于 2011-12-15T01:22:13.100 に答える
0

それは言語の非常にひどいろくでなし化ですが、方法はあります。基本的に、必要なシグネチャが既にあるクラスにインターフェイスを適用しようとしていると仮定します。(例のように) サブセットが必要なだけです。

TransparentProxy/RealProxy ペアを使用して、任意のインターフェイス (または MarshalByRef オブジェクト) を実装するクラスを実行時に作成できます。呼び出しを処理するために実装する必要がある抽象メソッドがありますが、少し手間をかければ、この種の状況を処理できるように十分に一般的なものにすることができます。

非常にうまくラップされていないライブラリで同様の問題に遭遇しました (すべてのメソッド呼び出しを行うためにリフレクションを使用する必要がありました)。そのため、大量のカスタム リフレクション コードを書き出すのではなく、一般的なケースを記述してから、シグネチャに一致する一連のインターフェイスを記述しました。次に、インターフェイスを直接使用しました。オブジェクトを自動的にラップ/ラップ解除することもできるので、インターフェイス メソッドが他のインターフェイスを返すようにするだけで、すべてが機能します。

http://blog.paulhounshell.com/?s=Duckに方法論と実装の非常に長い記事があります。

于 2011-12-15T01:48:07.383 に答える
0

@MBabcock のコメントのおかげで、私はこれが間違っていると考えていたことに気付きました。次のように、インターフェイスを完全なクラスに昇格させました。

public class Lookup<K, V>
{
    private readonly Func<K, V> lookup;
    protected Lookup(Func<K, V> lookup)
    {
        this.lookup = lookup;
    }

    public static implicit operator Lookup<K, V>(Dictionary<K, V> dict)
    {
        return new Lookup<K, V>(k => dict[k]);
    }

    public V this[K key]
    {
        get { return lookup(key); }
    }
}

このようにさらに変換が必要な場合は、暗黙の演算子を追加するだけです

于 2011-12-15T01:25:55.520 に答える
0

あなたができる最善のことは、拡張メソッドとラッパークラスを使用することです...

public interface ILookup<K, V>
{
    V this[K key] { get; }
}

public class DictWrapper<K, V> : ILookup<K, V>
{
    Dictionary<K, V> dictionary;

    public DictWrapper(Dictionary<K, V> dictionary)
    {
        this.dictionary = dictionary;
    }

    public V this[K key]
    {
        get { return dictionary[key]; }
    }

    protected internal Dictionary<K, V> InnerDictionary { get { return dictionary; } }
}

public static class Extensions
{
    public static ILookup<K, V> ToLookup<K, V>(this Dictionary<K, V> dictionary)
    {
        return new DictWrapper<K, V>(dictionary);
    }
}

class Program
{
    static void Main(string[] args)
    {
        Dictionary<string, int> data = new Dictionary<string, int>();

        data.Add("Office", 100);
        data.Add("Walls", 101);
        data.Add("Stair", 30);

        ILookup<string, int> look = data.ToLookup();
    }
}
于 2011-12-15T01:40:29.467 に答える