5

この質問を読みやすく/理解できるようにする方法は正確にはわかりませんが、私の意見を聞いてください。最後に私の問題を理解していただけることを願っています (少なくとも、簡単に再現可能です)。

UnitTests で結果を検証するために使用されるメソッドを呼び出そうとします。次の署名があります。

void AssertPropertyValues<TEnumerable, TElement, TProperty>(
  TEnumerable enumerable, 
  Func<TElement, TProperty> propertyPointer, 
  params TProperty[] expectedValues) 
  where TEnumerable : System.Collections.Generic.IList<TElement>

これが意味することは、次の入力を取るということです

  1. 列挙可能で、2) の入力と同じタイプのオブジェクトを含むオブジェクト。
  2. 1) の「内容」と同じ Type のオブジェクトを取り、3) で提供される配列の内容の Type と同じ Type のオブジェクトを返す Func (通常はラムダ式をカプセル化する)。
  3. 2) の Func の出力と同じ Type のオブジェクトの配列。

したがって、このメソッドの実際の実行は次のようになります。

AssertPropertyValues(
  item.ItemGroups, 
  itemGroup => itemGroup.Name, 
  "Name1", "Name2", "Name3");

少なくとも、それは私がどのように見えるかを望んでいますが、よく知られているコンパイラ エラーに遭遇します:「メソッド 'X' の型引数は、使用法から推測できません。」、そしてそれは私がしていないことです。理解する。私が見る限り、必要なすべての情報が含まれているはずですか、それとも「共分散と反分散」の問題の別のバージョンでしょうか?

したがって、今のところ、代わりに次のようにする必要があります。

AssertPropertyValues(
  item.ItemGroups, 
  (ItemGroup itemGroup) => itemGroup.Name, 
  "Name1", "Name2", "Name3");

このシナリオがコンパイラによって推論されない理由を誰でも指摘できますか?

4

1 に答える 1

24

あなたの問題は、制約が署名の一部と見なされず、型推論中に推論を行うために使用されないという事実によって引き起こされます。あなたは推論が進むことを期待しています:

  • TEnumerable最初の引数の型を取ることによって決定されます。
  • TElementIList<T>から実装情報を取得することによって決定されますTElement
  • TPropertyラムダの本体の型によって決定されます

しかし、制約からの情報を考慮する必要があるため、C# はその 2 番目のステップを実行しません。お気づきのように、ラムダでその情報を提供すると、コンパイラは仮パラメーターの型に基づいて推論を行います。

幸いなことに、あなたの制約は完全に不要です。メソッドを書き直して、制約のないより単純な署名を作成します。

void AssertPropertyValues<TElement, TProperty>(
  IList<TElement> sequence, 
  Func<TElement, TProperty> projection, 
  params TProperty[] expectedValues)

そして今、あなたは大丈夫なはずです。

そして、あなたがそれに取り組んでいる間、何らかの理由で IEnumerable<TElement>必要でない限り、おそらくそれを単純化する必要があります.IList<T>

于 2013-07-16T13:19:42.600 に答える