12

したがって、IEnumerable のかなり一般的な拡張メソッドである Run:

public static IEnumerable<T> Run<T>(this IEnumerable<T> source, Action<T> action)
{
    foreach (var item in source)
    {
        action(item);
        yield return item;
    }
}

たとえば、DbSet.Add でそれを使用しようとすると:

invoice.Items.Run(db.InvoiceItems.Add);
// NB: Add method signature is
// public T Add(T item) { ... }

...コンパイラは、voidメソッドを期待しているため、戻り値の型が間違っていると不平を言います。したがって、Action の代わりに Func を取る Run のオーバーロードを追加します。

public static IEnumerable<T> Run<T>(this IEnumerable<T> source, Func<T, T> action)
{
    return source.Select(action).ToList().AsEnumerable();
}

そして今、コンパイラは「呼び出しは次のメソッド間であいまいです...」と不平を言います...

私の質問は、Run メソッドの Action オーバーロードがメソッド グループに対して有効でない場合、どのようにあいまいさを引き起こすのでしょうか?

4

4 に答える 4

5

これは、この質問への回答でエリックとジョンによってすでに説明されています。簡単に言えば、これが C# コンパイラのしくみです。正確には、メソッド グループの変換を処理するときに、どのデリゲートに変換するかを決定する際に、戻り値の型を考慮しないオーバーロードの解決を利用します。

ここでの原則は、メソッド グループの変換可能性を判断するには、オーバーロードの解決を使用してメソッド グループからメソッドを選択する必要があり、オーバーロードの解決では戻り値の型は考慮されないということです。

あなたの例では、コンパイラは と の両方Action<T>Func<T, T>最適なものとして認識しますAdd。これにより、可能な選択肢が最大 2 つになり、1 つが必要になるため、適切なエラーが発行されます。

于 2012-06-27T12:24:23.853 に答える
0

正しい方法でオーバーロードを試してください:

public static IEnumerable<TDest> Run<TSource, TDest>(this IEnumerable<TSource> source, 
    Func<TSource, TDest> action) 
{ 
 return source.Select(action).ToList(); 
} 
于 2012-06-27T11:29:37.497 に答える
0

理由はわかりませんが、あいまいさを解決するために、関数を明示的にキャストできます。

invoice.Items.Run((Func<T,T>)db.InvoiceItems.Add); 

またはラムダを使用する

invoice.Items.Run(x => db.InvoiceItems.Add(x));
于 2012-06-27T11:43:21.473 に答える
0

自動的に解決できない理由はわかりませんが、次の 2 つの回避策があります。

// with T replaced with the actual type:
invoice.Items.Run((Func<T, T>)db.InvoiceItems.Add);
invoice.Items.Run(new Func<T, T>(db.InvoiceItems.Add));

とにかく、なぜこれらのメソッドが必要なのですか? どうしたの:

foreach (var item in invoice.Items)
    db.InvoiceItems.Add(item);

読みやすさはこちらの方が上です。メソッドが必要な正当な理由がない限り、Run使用しないことをお勧めします。私が見たところ、少なくともAction<T>過負荷については、そのような理由はありません。

于 2012-06-27T11:45:00.127 に答える