12

は、私は2つの拡張メソッドがあります:拡張メソッドのオーバーロードの選択

public static IPropertyAssertions<T> ShouldHave<T>(this T subject) 
{ 
    return new PropertyAssertions<T>(subject); 
} 

public static IPropertyAssertions<T> ShouldHave<T>(this IEnumerable<T> subject) 
{ 
    return new CollectionPropertyAssertions<T>(subject); 
} 

を今私はそれを使用するいくつかのコードを記述します。

List<Customer> collection2 = new List<Customer>(); 
collection2.ShouldHave(); //first overload is chosen 
IEnumerable<Customer> collection3 = new List<Customer>(); 
collection3.ShouldHave(); //second overload is chosen 

2番目のオーバーロードは、私は明示的にIEnumerableをタイプを指定した場合にのみ選択されています。どちらの場合でも2番目の過負荷を選択する方法はありますか?

+0

'collection1'と' collection2'には違いはありません。それらはまったく同じコードであり、異なる書式しか書かれていません。 – svick

+0

@svick、はい、すべての構文オプションを表示したい – SiberianGuy

+3

拡張メソッドであるという事実は無関係です。オーバーロードの解決は通常の静的メソッドのように扱います。 –

答えて

5

そう思わないでください。 の中での場合はのように、常にIEnumerable<T>のオーバーロードが呼び出される可能性は考えられませんのタイプの正確な一致があります。具体的なIEnumerable<T>を指定しない場合は、最も良い一致が常にの場合の最初の方法になります。

7

Tはと推測されるため、最初のオーバーロードはより正確です。これは完全一致です。 2番目の過負荷の場合、TはCustomerと推定されるため、パラメータはIEnumerable<Customer>となり、これはList<Customer>よりも正確に一致しません。

1

ShouldHave()は二重の意味を持ちます。最初のケースでは、ShouldHave()は、subject-parameterによって指定されたオブジェクトについての戻り値を持ちます。 2番目のケースでは、戻り値は列挙内の項目についてのものであり、列挙自体についてのものではありません。

私自身のコレクションを作成し、このコレクション自体(アイテムではない)をテストしたい場合は、ShouldHave(このTサブジェクト)を呼び出す必要があり、ShouldHave(このIEnumerableサブジェクト)ではありません。

あなたのデザインを再考する必要があります。 2番目のShouldHave()は2つのことを行います。したがって、コレクション項目を抽出するメソッドと、既に持っている最初のShouldHave()の呼び出しに分割する必要があります。

+0

それはまさに私たちが試みているこれを行うには、C#コンパイラのオーバーロード解決にいくつか問題があります。 –

+0

C#コンパイラは、まず型キャストが必要なマッチより完全なマッチを優先します。私はあなたのデザインが不完全だと思うし、あなたはそれもC#のコンパイラが不完全なことによって解決したい。 本当にShouldHave(このT件名)を自分のコレクションに適用したいのですが?なぜこのシナリオをブロックしたいのですか? –

+0

私は不完全なのが好きです:-) –