为什么方法类型推断无法推断类型参数
本文关键字:类型参数 方法 为什么 类型 | 更新日期: 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>
这意味着,它接受以下输入
- 任何可枚举的对象,并且包含与2)的intput类型相同的对象
- 一个Func(通常封装lambda表达式),它接受一个与1)的"内容"类型相同的对象,并返回一个与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>
。