私は2つの拡張メソッドを書いています。 1つは単一のオブジェクトで作業し、もう1つはオブジェクトの集合で作業します。拡張メソッドを呼び出すと、C#コンパイラはどちらを使用するのか混乱し、コンパイルに失敗します。C#拡張メソッドのコンパイル/名前空間の順序に基づく互換性チェックが失敗する
さらに驚くべきことに、拡張メソッドを異なる名前空間に移動すると、両方の名前空間をコールサイトに含めるとしても、名前空間がアルファベット順に特定の順序である場合にのみコンパイルが失敗します。ここで
はコードです:
public static class DBObjectExtensions
{
public static void PopulateRelations<T>(this T obj, params RelationToPrefetch[] relationsToPrefetch) where T : IDBObject
{
if (obj == null)
{
return;
}
obj.Transaction.PopulateRelations<T>(new[]{ obj }, relationsToPrefetch);
}
public static void PopulateRelations<T>(this IEnumerable<T> objects, params RelationToPrefetch[] relationsToPrefetch) where T : IDBObject
{
var first = objects.FirstOrDefault();
if (first == null)
{
return;
}
first.Transaction.PopulateRelations<T>(objects, relationsToPrefetch);
}
}
これは、コンパイルを失敗した呼び出し場所ラインです:
型「にSystem.Collections:
List<ITable> list = ... // ITable inherits from IDBObject list.PopulateRelations(xxx);
はエラーCS0311で失敗します。ジェネリック型またはメソッド 'Granta.MI.DBObjectExtensions.PopulateRelations(T、params Granta.MI。)の型パラメータ' T 'として使用することはできません。 RelationToPrefetch []) 'を呼び出します。 'System.Collections.Generic.List'から 'Granta.MI.IDBObject'への暗黙的な参照変換はありません。
2番目の拡張メソッドを削除すると、この行はコンパイルに成功します。マッチングの拡張メソッドがあり
public static void PopulateRelations<T>(this List<T> objects, params RelationToPrefetch[] relationsToPrefetch) where T : IDBObject
{
((IEnumerable<T>)objects).PopulateRelations(relationsToPrefetch);
}
public static void PopulateRelations<T>(this IList<T> objects, params RelationToPrefetch[] relationsToPrefetch) where T : IDBObject
{
((IEnumerable<T>)objects).PopulateRelations(relationsToPrefetch);
}
できないのはなぜコンパイラのフィギュアから:
も(...コレクションのすべての可能なタイプのために)トランポリンの方法を書いても動作することに注意してください?もっと混乱して、別の名前空間にメソッドの1つを入れ、その名前空間を組み込むと、なぜコンパイルが成功するのでしょうか?これを解決するために何かできることはありますか?
オーバーロードの解決には制約がありません。さらに、メソッド関数の中で 'T'が必要ないように思えますが、単に' IDbObject'を使うのではなく、あなたの拡張に 'T'を使う必要がありますか? – Jcl
拡張メソッドの中で 'T'を必要としない場合、単に@ jakub-lortzのようなメソッドを変更するだけで、@ Jclの人々は' T'を使うと非常に混乱します。 – mijail
謝罪 - 私は答えにそれをしない理由を含めなかった。その理由は、 'Transaction.PopulateRelations'もT型をとり、' typeof'を呼び出すため、Tが 'IDBObject'だけでなく具体的な型である必要があるからです。 –