为什么方法类型推断无法推断出类型参数?

Joh*_*dal 5 c# generics lambda

我不确定如何使这个问题可读/可理解,但听到我的意见,我希望你能在我们结束时理解我的问题(至少,它很容易重现).

我尝试调用一个用于在UnitTests中验证结果的方法.它有以下签名:

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

这意味着,它需要以下输入

  1. 任何可枚举的对象,包含与2的intput相同类型的对象.
  2. 一个Func(通常封装lambda表达式),它接受与1)的"contents"相同类型的对象,并返回与3)中提供的数组内容类型相同的Type类型的对象.
  3. 与2)中Func的输出相同类型的对象数组.

因此,此方法的实际执行可能如下所示:

AssertPropertyValues(
  item.ItemGroups, 
  itemGroup => itemGroup.Name, 
  "Name1", "Name2", "Name3");
Run Code Online (Sandbox Code Playgroud)

至少,这就是我希望它看起来像,但我遇到了众所周知的编译器错误:"方法'X'的类型参数不能从使用中推断出来.",这就是我不知道的了解.它应该具有我所能看到的所有信息,或者它可能是"协方差和反演"问题的另一个版本?

所以现在我不得不这样做:

AssertPropertyValues(
  item.ItemGroups, 
  (ItemGroup itemGroup) => itemGroup.Name, 
  "Name1", "Name2", "Name3");
Run Code Online (Sandbox Code Playgroud)

任何人都可以指出为什么编译器无法推断出这种情况?

Eri*_*ert 24

您的问题是由于约束不被视为签名的一部分而且永远不会用于在类型推断期间进行推断.您期望推断:

  • TEnumerable 取决于第一个参数的类型.
  • TElement通过IList<T>从中获取实施信息来确定TElement
  • TProperty 由λ体的类型决定

但是C#从未迈出第二步,因为这需要考虑来自约束的信息.如您所知,如果您在lambda中提供该信息,则编译器会根据形式参数类型进行推导.

幸运的是,您的约束完全没有必要.重写您的方法以使更简单的签名没有约束:

void AssertPropertyValues<TElement, TProperty>(
  IList<TElement> sequence, 
  Func<TElement, TProperty> projection, 
  params TProperty[] expectedValues)
Run Code Online (Sandbox Code Playgroud)

现在你应该没事.

虽然你在这里,你应该简化它,IEnumerable<TElement>除非你IList<T>出于某种原因需要.