扩展方法调用不编译,但静态方法调用相同的代码确实编译

库A调用库B使用C#扩展方法。

我从C#编译器得到了一个奇怪的错误:

类型’System.Windows.Forms.Control’在未引用的程序集中定义。 您必须添加对程序集’System.Windows.Forms,Version = 4.0.0.0的引用

库A或B都不依赖于System.Windows.Forms.Control ,也没有任何依赖于System.Windows.Forms.Control的依赖关系。 System.Windows.Forms.Control仅从同一解决方案中的另一个项目引用。

奇怪的是,如果我将调用语法更改为静态方法,它将成功编译。

 //static method syntax works fine var leads = SourceLeadConfigurationHelper.GetLeads(enLeadSystem); //extension method syntax cause error //error The type 'System.Windows.Forms.Control' is defined in an assembly that is not referenced. var leads = enLeadSystem.GetLeads(); 

扩展方法如下所示:

 public static class SourceLeadConfigurationHelper { public static IList GetLeads(this LeadSystem leadSystem); public static IList GetLeads(this SourceLeadConfiguration slc); public static IList GetLeads(LeadSystem leadSystem, bool throwException); } 

所以你看到检测使用哪个扩展没有问题。 LeadSystem是一个枚举, SourceLeadConfiguration是一个类。

我有Visual Studio 2013更新5,.NET Framework 4.0。

这是一个关于C#编译器行为的非常一致的抱怨,驱动程序员非常疯狂。 不幸的是,没有规范的Q + A,每种情况都不同。 它的第一个报告开始出现在VS2012 / .NET 4.5时间框架周围。 编译器不习惯这样做,它闻起来像一个比预期更大的bug修复。 我们也没有经常听到它,大多数程序员只是按照错误消息中的指导并添加程序集引用。 所以,你应该解决这个问题。

试着在这里描述一下它。 它与扩展方法没有直接关系,此行为特定于方法重载解析。 扩展方法只是它的一个特例,肯定是一个棘手的案例。

找到一个方法重载匹配并不是特别棘手,它会在过载不明确时生成一个合适的错误消息。 关于改变行为的一个非常明确的事情是编译器现在更加彻底。 它坚持要知道关于论证类型的一切 。 即使程序员的眼睛清楚地知道传递的参数不可能与另一个未引用的汇编中的类型相匹配。 但编译器对它很苛刻,如果它不知道类型,那么它坚持你添加引用。

扩展方法很棘手,因为可能有很多,而不仅仅是SourceLeadConfigurationHelper.GetLeads(),你(显然)希望选择它。 程序集可能会定义其他扩展方法,它们可能只会向SourceLeadConfiguration类型添加更多扩展方法。 如果编译器知道程序集存在,但不知道它看起来是什么样的,因而无法知道它可能包含哪些扩展方法,那么它会抱怨。 请注意这是如何解释为什么在直接调用静态方法时不会出现错误的原因,编译器无需查找扩展。

您肯定可以猜测编译器如何找到有关System.Windows.Forms程序集的信息。 它是由另一个程序集引入的,你提到但未描述的那个程序集。 诊断是System.Windows.Forms.Control类型泄露在该程序集的元数据中。 通常作为公共方法的参数或返回类型。 你必须在源代码中进行一些挖掘才能找到它,否则你可以消除它的冲击力。


关于可能与此相关的扩展方法的另一个细节,ExtensionAttribute类型在.NET 4.5中从System.Core.dll移动到mscorlib.dll。 这是一个相当大的变化,当程序员没有正确构建程序集时,会导致很多问题。 如果您的目标是.NET 4.0,那么您需要仔细检查一下,详情请点击此处 。


希望你可以从引用Winforms的程序集中追逐它。 如果没有,或者你无法消除曝光,那么添加引用实际上就是保持编译器满意的全部内容。