扩展方法调用不编译,但是静态方法调用相同的代码不编译 [英] Extension method call does not compile, but static method call to same code does compile

查看:262
本文介绍了扩展方法调用不编译,但是静态方法调用相同的代码不编译的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

There is library A calling library B using a C# extension method.

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

I got a weird error from the C# compiler:


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

The type 'System.Windows.Forms.Control' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Windows.Forms, Version=4.0.0.0

A或B依赖于 System.Windows.Forms.Control ,也没有A的依赖关系对 System.Windows.Forms.Control System.Windows.Forms.Control 只能从同一解决方案中的另一个项目引用。

None of the libraries A or B are dependent on System.Windows.Forms.Control, nor has any dependency of A a dependency on System.Windows.Forms.Control. System.Windows.Forms.Control is only referenced from another project in the same solution.

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

The weird thing is that if I change the call syntax to static method, it compiles successfully.

//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 是一个类。

So you see there is no problem with detecting which extension to use. LeadSystem is an enum, SourceLeadConfiguration is a class.

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

I have Visual Studio 2013 update 5, .NET Framework 4.0.

推荐答案

驱动程序员相当疯狂。不幸的是,没有规范的Q + A为它,每一种情况是不同的。它的第一个报告开始显示在VS2012 / .NET 4.5时间框架。编译器没有使用这种方式,它的味道像一个bug修复,比预期更大的影响。我们也不会经常听到它,大多数程序员只是按照错误消息中的指导并添加程序集引用。所以,你应该,它trivially解决问题。

This is a pretty consistent complaint about C# compiler behavior, drives programmers pretty nutty. Unfortunately there is no canonical Q+A for it, every case is different. The first reports of it started showing up around the VS2012/.NET 4.5 time frame. The compiler did not used to behave this way, it smells like a bug fix that had a bigger impact than anticipated. We also don't hear about it often enough, most programmers just follow the guidance in the error message and add the assembly reference. So should you, it trivially solves the problem.

尝试在这里描述一下。它不直接与扩展方法有关,这种行为是特定于方法重载分辨率。

Trying to characterize it a bit here. It doesn't directly have anything to do with extension methods, this behavior is specific to method overload resolution. Extension methods are just a special case of it, a tricky case for sure.

找到一个方法重载匹配不是特别棘手,它生成一个错误的错误消息,当重载是模糊的,这是问题。有一点很清楚,改变的行为是编译器现在更彻底。它坚持要知道有关参数类型的一切。即使程序员的眼睛很清楚,传递的参数不可能匹配另一个未引用的程序集中的类型。但是编译器是关于它的,如果它不知道类型,那么它坚持你添加引用。

Finding a method overload match is not particularly tricky, it is generating a decent error message when the overload is ambiguous that is the problem. One thing that's quite clear about the changed behavior is that the compiler is now more thorough. It insists on knowing everything about the type of an argument. Even if it is crystal clear to programmer's eyes that the passed argument cannot possibly match a type in another unreferenced assembly. But the compiler is pig-headed about it, if it does not know the type then it insists you add the reference.

扩展方法是棘手的,因为可能有很多,不仅仅是SourceLeadConfigurationHelper.GetLeads(),你(显然)期望被挑选。程序集可能定义其他扩展方法,并且可能向SourceLeadConfiguration类型添加更多扩展方法。如果编译器知道程序集存在,但不知道它是什么样子,因此不知道它可能包含什么扩展方法,那么它会抱怨。注意这怎么解释为什么你直接调用静态方法时没有得到错误,没有必要让编译器去寻找扩展。

Extension methods are tricky because there might be many, not just the SourceLeadConfigurationHelper.GetLeads() one you (obviously) expected to be picked. An assembly might define other extension methods, and they just might add more extension methods to the SourceLeadConfiguration type. If the compiler knows the assembly exists, but does not know what it looks like, and thus can't know what extension methods it may contain, then it will complain. Note how this explains why you don't get the error when you call the static method directly, there is no need for the compiler to go look for extensions.

你可以肯定猜测编译器如何找到System.Windows.Forms程序集。它是由其他大会介绍的,你提到但没有描述。诊断是在该程序集的元数据中泄露了System.Windows.Forms.Control类型。通常作为公共方法的参数或返回类型。你必须在源代码中进行挖掘才能找到它,否则就不能使用slamdunk来消除它。

You can surely guess how the compiler got to find out about the System.Windows.Forms assembly. It got introduced by the other assembly, the one you mentioned but did not describe. The diagnostic is that the System.Windows.Forms.Control type leaked out in the metadata of that assembly. Usually as an argument or return type of a public method. You'll have to do some digging in the source code to find it, not otherwise a slamdunk that you can eliminate it.

可能有关的扩展方法的另一个细节细节,ExtensionAttribute类型在.NET 4.5从System.Core.dll移动到mscorlib.dll。一个相当大的变化,当程序员没有正确构建它们的程序集时,引起了很多问题。如果您定位到.NET 4.0,则需要仔细检查,位于此处

One more gritty detail about extension methods that might be relevant here, the ExtensionAttribute type was moved in .NET 4.5 from System.Core.dll to mscorlib.dll. A rather heavy change and one that has caused lots of problems when programmers don't build their assemblies correctly. If you target .NET 4.0 then you'll want to double-check this, details are here.

希望你可以从引用Winforms的程序集中追逐它。如果没有,或者你不能消除曝光,那么添加引用是真正需要保持编译器的快乐。

Hopefully you can chase it down from the assembly that references Winforms. If not, or you can't eliminate the exposure, then adding the reference is really all it takes to keep the compiler happy.

这篇关于扩展方法调用不编译,但是静态方法调用相同的代码不编译的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆