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

时间:2016-03-09 09:14:57

标签: c# compiler-errors extension-methods

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

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

  

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

库A或B都不依赖于System.Windows.Forms.Control,也不依赖于A依赖System.Windows.Forms.ControlSystem.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<ChannelID> GetLeads(this LeadSystem leadSystem);
    public static IList<ChannelID> GetLeads(this SourceLeadConfiguration slc);
    public static IList<ChannelID> GetLeads(LeadSystem leadSystem, bool throwException);
}

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

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

1 个答案:

答案 0 :(得分:7)

这是一个关于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,那么您需要仔细检查一下,详细信息are here

希望你可以从引用Winforms的程序集中追逐它。如果没有,或者你无法消除曝光,那么添加引用就足以让编译器满意。