10

次のコード セグメントを確認してください。

public interface ICountable { }
public class Counter<T>
    where T : ICountable
{
    public int Count(IEnumerable<T> items)
    {
        return 0;
    }

    public int Count(T Item)
    {
        return 0;
    }
}

public class Counter
{
    public int Count<T>(IEnumerable<T> items)
        where T : ICountable
    {
        return 0;
    }

    public int Count<T>(T Item)
        where T : ICountable
    {
        return 0;
    }
}

Counter の 2 つのバージョンは、ジェネリック パラメーターの仕様のみが異なります。1 つはジェネリック型パラメーターとして定義され、もう 1 つはジェネリック引数として定義されます。どちらもメソッド引数を制限して ICountable インターフェイスを実装します。それらをそれぞれ特定および非特定と呼びます。

ここで、 ICountableインターフェイスとインスタンスのコレクションを実装するクラスを定義しています。

public class CItem : ICountable { }
var countables = new List<CItem>();

次に、コレクションで両方の Counter クラスを使用したいと思います。

var specific = new Counter<CItem>();
var nonspecific = new Counter();

specific.Count(countables);
nonspecific.Count(countables);

特定のカウンターは、 countablesコレクションが署名int Count(IEnumerable)に分類される必要があることを認識しますが、非特定のバージョンはそうではありません。エラーが発生します:

型 ' ' は、ジェネリック型またはメソッド ' ' のSystem.Collections.Generic.List<CItem>型パラメーター ' ' として使用できません。' から への暗黙的な参照変換はありません 。TCounter.Count<T>(T)List<CItem>ICountable

特定されていないバージョンがコレクションに間違った署名を使用しているようです。

なぜ彼らは異なる振る舞いをするのですか?他のバージョンと同じように動作するために、特定されていないバージョンをどのように指定できますか?

注: この例が現実的でないことはわかっています。ただし、拡張メソッドを使用した非常に複雑なシナリオでこの問題に直面しました。簡単にするためにこれらのクラスを使用します

前もって感謝します

4

3 に答える 3

2

私の記憶が正しければ (仕様で参照を見つけようとします)、T型に完全に一致するメソッドが選択されます。

型推論は、 と のように、両方のジェネリック メソッドが適用可能であることを正しく識別しCount<CItem>(IEnumerable<CItem> items)ますCount<List<CItem>>(List<CItem> items)。ただし、2 番目の方がより具体的であるため、1 番目の方はオーバーロードの解決に失敗します。制約はその後にのみ有効になるため、コンパイル時にエラーが発生します。

countables使用を宣言する場合

IEnumerable<CItem> countables = new List<CItem>();

その後、選択肢はCount<CItem>(IEnumerable<CItem> items)andCount<IEnumerable<CItem>>(IEnumerable<CItem> items)になり、最初の選択肢がオーバーロードの解決に勝ちます。

于 2015-12-16T11:08:55.307 に答える