3

ネストされたジェネリックを使用する場合、コンパイラは直接使用すると失敗しますが、制約を使用すると正しくコンパイルされます。

例:

public static void Test1<V, E>(this Dictionary<V, E> dict)
    where V : IVertex
    where E : IEdge<V>
{}

public static void Test2(this Dictionary<IVertex, IEdge<IVertex>> dict){}

上記の 2 つの拡張メソッドは、表向きは同じシグネチャを持っていますが、次のようなコードを実行しようとすると、次のようになります。

var dict = new Dictionary<VertexInstance, EdgeInstance>();

dict.Test1();
dict.Test2();

コンパイラは、'Test2' で、インラインでネストされたジェネリックを使用してジェネリック形式に変換できないことを示すエラーを出します。個人的には、の構文のTest2方が直感的だと思います。

これはもともと、一般的な制約を使用することとインターフェイスを直接使用することの違いについて尋ねた質問の回答として投稿しましたが、なぜこれが起こるのか興味がありますか?

4

1 に答える 1

4

私のコメントを展開する:

もちろん、これらの拡張メソッドには同じ署名はありません。Dictionary<IVertex, IEdge<IVertex>>と同じではありませんDictionary<VertexInstance, EdgeInstance>。@Payoは正しいです。これは分散の問題です。クラスを共変または反変にすることはできません。インターフェイスはマークされている場合に限り可能ですが、IDictionary は安全ではないためマークできないため、IDictionary に変更してもここでは役に立ちません。

これが許可されているかどうかを検討してください。Test2 の実装は次のようになります。

public static void Test2(this Dictionary<IVertex, IEdge<IVertex>> dict)
{
    dict.Add(new EvilVertex(), new EvilEdge());
} 

EvilVertex と EvilEdge は正しいインターフェイスを実装できますが、VertexInstance と EdgeInstance から継承することはできません。その後、呼び出しは実行時に失敗します。したがって、Test2 の呼び出しは安全であることが証明されていないため、コンパイラはそれを許可しません。

答えてくれてありがとう; ただし、制約バージョンには同じコードが含まれている可能性があり、同じ問題が発生する可能性がありますね。

いいえ!から に変換することも、からに変換することもできないため、制約バージョンに同じコードを内部に含めることはできませんでした。最初に にキャストすることにより、型から型パラメーターへのキャストを強制できますが、もちろん実行時に失敗します。EvilVertexVEvilEdgeEobject

また、分散がそのレベルで制御されるのはなぜですか?

ジェネリックの目的の 1 つは、コンパイル時にコードの型安全性を証明することだからです。

あなたの dict.Add には、私の見解では拡張メソッドではなくコンパイルエラーが含まれているはずです。

前述のように、dict Add の呼び出し、ジェネリック バージョンのコンパイラ エラーです。Test2 のコンテキストでは、EvilVertex を IVertex に変換していることしかわかりませんが、これは完全に合法です

于 2012-04-16T20:49:33.107 に答える