当使用动态参数调用泛型扩展方法时,C#编译器会因错误而失败

当使用动态参数调用泛型扩展方法时,C#编译器会因错误而失败,c#,generics,dynamic,compiler-errors,C#,Generics,Dynamic,Compiler Errors,在阅读Jon Skeet的书《深入第四版》时,我做了一些与扩展方法相关的动态绑定限制测试。 正如Jon在那一章中所说,.NET中的扩展方法不支持动态绑定,因此编译器通过引发适当的错误来阻止我们将动态值作为参数传递。因此,对于以下代码: //Provided this extension method public static int GetFoo(this List<int> target, int value) => value * 10; //And the follo

在阅读Jon Skeet的书《深入第四版》时,我做了一些与扩展方法相关的动态绑定限制测试。 正如Jon在那一章中所说,.NET中的扩展方法不支持动态绑定,因此编译器通过引发适当的错误来阻止我们将动态值作为参数传递。因此,对于以下代码:

//Provided this extension method
public static int GetFoo(this List<int> target, int value) => value * 10;

//And the following code at the call site
dynamic d = 1;
var items = new List<int> { 1, 2, 3 };
var result = items.GetFoo(d); //Error CS1973 as expected because
                              //we passed a dynamic argument
在我看来,错误信息是误导性的,也是毫无意义的:

List
不包含
GetFooGeneric
和最佳 扩展方法重载
扩展。GetFooGeneric(List,int)
需要类型为
List
的接收器

误导性,因为它隐藏了对扩展方法的动态绑定的不支持,并且将类型为
List
的实例作为调用扩展方法的接收者是没有意义的

有人知道幕后发生了什么,导致编译器发出这种误导性错误消息吗?


PS:作为旁注,如果我们为相同的泛型方法提供类型参数,那么编译器会按照预期再次引发相应的错误CS1973

//By helping the compiler explicitly, it raises CS1973 appropriately
var result = items.GetFooGeneric<int>(d);
//通过显式地帮助编译器,它可以适当地引发CS1973
var结果=items.GetFooGeneric(d);

您编写:
GetValueGeneric(此列表目标,int值)
注意您编写的value

调用
items.GetFooGeneric(d)将导致CS1929,因为您的函数不存在


我尝试
items.GetValueGeneric(d)并且它给出了CS1973

哎哟。真糟糕!我不记得这是不是我的错,但你肯定是对的,这是一个可怕的错误信息

这可能是我们在分析器中使用了一些启发式方法的结果,以处理您在编辑器中实际键入代码的情况,并且我们需要对扩展方法的不完整或错误调用进行类型推断,以便获得正确的IntelliSense;也许这与动态参数的交互不好?但我需要实际查看代码以刷新那里的内存

如果我今天晚些时候有时间,我将查看Roslyn的源代码,看看我是否识别出这个代码路径


我知道这并不能很好地回答您的问题,但至少从2012年起,我就没有调试过该代码路径,因此我对这些设计选择的回忆与以前不同了。:)

当您为
List
创建扩展方法时,如果不告诉方法什么是
T
,就不能为
List
调用它。这就是为什么您可以使用
GetFooGeneric
调用<代码>最佳扩展方法重载扩展。GetFooGeneric(List,int)需要一个List类型的接收者。
错误消息说了同样的事情。如果我自己使用
dynamic
,那么我只需调用
items.GetFooGeneric((int)d)
。当您混合了几个错误时,编译器会告诉您一些意想不到的事情。您看到的错误是由另一个类似的场景产生的,该场景没有
dynamic
,它可能非常有效。由于您添加了
动态
,因此会出现令人困惑的错误,这是您的错误。@ChetanRanpariya在大多数情况下,编译器能够推断
T
的类型,即使在这里,如果我们为
int value
参数传递一个静态类型的参数,情况也是如此。另一个常见的类型推断示例是,当您在
列表
@Sinatr上调用linq方法时,我同意将
d
强制转换为
int
将完全消除我设计的示例中的动态绑定问题。但是,如果
参数的类型也为
动态
,如下所示
GetFooGeneric(List,dynamic)
?这仍然会引发错误CS1929,这会误导我们远离真正的问题(扩展方法不支持动态绑定)。方法参数
int-Value
只是一个整型参数。它与
T
无关。因此,它不能在编译时将
T
推断为整数。实际上,当我将自己的代码修改为可邮寄时,这是一个错误的匹配错误。即使如此,它也会引发错误CS1061。谢谢你指出这个复制粘贴错误。我不确定是否有误,但我没有足够的声誉来评论
//By helping the compiler explicitly, it raises CS1973 appropriately
var result = items.GetFooGeneric<int>(d);