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

本文关键字:类型参数 方法 为什么 类型 | 更新日期: 2023-09-27 18:22:40

我不确定如何让这个问题变得可读/可理解,但听听我的意见,我希望当我们讨论到最后时,你会理解我的问题(至少,它很容易复制)。

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

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

这意味着,它接受以下输入

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

因此,这个方法的实际执行可能是这样的:

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

至少,我希望它是这样的,但我遇到了一个众所周知的编译器错误:"无法从用法中推断出方法'X'的类型参数。",这就是我不理解的。据我所见,它应该有所有需要的信息,或者它可能是"协方差和方差"问题的另一个版本?

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

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

有人能指出为什么编译器不能推断出这种情况吗?

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

您的问题是由以下事实引起的:约束不被视为签名的一部分,并且在类型推断过程中从未用于进行推导。你期待着推论:

  • CCD_ 1是通过采用第一个参数的类型来确定的
  • 通过从TElement获取IList<T>实现信息来确定TElement
  • TProperty由lambda的主体类型决定

但是C#从不做第二步,因为这需要考虑来自约束的信息。正如您所注意到的,如果您在lambda中提供该信息,那么编译器将根据形式参数类型进行推导。

幸运的是,你的约束完全没有必要。重写您的方法以获得一个不受约束的更简单的签名:

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

现在你应该没事了。

当你在做的时候,你可能应该把它简化为IEnumerable<TElement>,除非你出于某种原因需要IList<T>

相关文章: