混合通用方法和扩展方法
我在Class1.GetChild<T>() where T : DependencyObject
创建了Class1.GetChild<T>() where T : DependencyObject
扩展方法。 之后,所有依赖lib1.dll的程序集都无法编译时出现错误:
类型'System.Windows.DependencyObject'被定义为可引用的,未被引用。 您必须添加对程序集“WindowsBase”等的引用...
为什么依赖程序集需要WindowsBase,即使它们不使用GetChild
?
。
重现(vs2010 .net4):
lib1.dll (引用WindowsBase)
namespace lib1
{
public static class Class1
{
public static T GetChild<T>(this DependencyObject src) where T : DependencyObject
{
return default(T);
}
}
public static class Class2
{
public static int SomeExtMethod(this string src)
{
return 0;
}
}
}
lib2.dll (引用lib1但不是WindowsBase)
using lib1;
class someClass
{
void someFct()
{
"foo".SomeExtMethod(); // error: The type 'System.Windows.DependencyObject'
// is defined in an assemebly that is not referenced.
// You must add a reference to assembly 'WindowsBase' etc..
}
}
。
更新:
我认为在混合泛型方法和扩展方法时有一些明确的东西。 我试图在下面的示例中演示该问题:
// lib0.dll
namespace lib0
{
public class Class0 { }
}
// lib1.dll
using lib0;
namespace lib1
{
public static class Class1
{
public static void methodA<T>() where T : Class0 { } // A
public static void methodB(Class0 e) { } // B
public static void methodC(this int src) { } // C
}
public static class Class2
{
public static void methodD(this String s) { }
}
}
// lib2.dll
using lib1;
class someClass
{
void someFct()
{
Class2.methodD(""); // always compile successfully
"".methodD(); // raise the 'must add reference to lib0' error depending on config. see details below.
}
}
A, //B, //C
- >编译好
A, B, //C
- >编译好
//A, B, C
- >编译好
A, //B, C
- >引发错误
A, B, C
- >引发错误
//A
装置methodA
被注释。 正如达米恩指出的那样,类型推断可能起一定的作用。 仍然好奇地知道这些来龙去脉。
您的情况已由Microsoft在这里回答:https://connect.microsoft.com/VisualStudio/feedback/details/668498/problem-with-extension-method-in-c-compiler
还有其他一些用例以及独立于错误地产生这个错误的扩展方法。
考虑这个:
如果您不使用TP1但在LB1中定义了其他类型,则不会收到错误。 此外,即使TP1类型的方法之一需要LB2中定义的类型的参数(并且您不调用此方法),它也不会产生此错误
当一个程序集依赖于另一个程序集时,第一个程序集也依赖于另一个程序集的所有依赖关系 - 不管使用什么。 程序集依赖关系有效地解耦,编译后可以部署另一个程序集版本,编译器无法知道在这种情况下,第一个程序集不会使用第二个程序集中的一个或多个依赖关系。
要解决这个问题,你可以简单地添加一个对WindowsBase的引用。
或者,正如prashanth指出的那样,将SomeExtMethod
放入不同的程序SomeExtMethod
以便使用该程序的代码不需要依赖WindowsBase。
更新:如果您不使用程序集中的任何内容,则不需要任何依赖关系。 但是,只要使用一个程序集,就需要该程序集的所有依赖关系。 这在Visual Studio添加引用的方式中很明显。 如果您添加对程序集的引用,它会将所有相关程序集(未在GAC中注册)复制到您添加的程序集的调试/版本目录中。
更新:至于编译错误:这是写它的方式 - 可能没有其他原因。 如果不引用相关程序集,是否会收到编译错误是个好主意? 也许,你可能会使用引用中的某些东西,并且可能会直接从引用引用中使用某些东西 - 编译错误比部署错误更好。
为什么不对每个未引用的辅助依赖项编译错误? 再次,它是这样写的。 也许这里的一个错误也是好的; 但这将是一个突破性的变化,需要真正有说服力的理由。
我不确定这可以由编译器团队以外的人解答。 我现在认为这是与类型推理有关 - 但是§7.6.5.1方法调用谈论了推理,§7.6.5.2扩展方法调用在这个问题上保持沉默 - 尽管事实上推理显然确实发生在搜索适用的扩展方法。
我认为它正在尝试某种形式的推理,然后才会对标识符进行比较(这会因为名称错误而立即排除扩展方法)。 显然,如果它无法理解类型约束,它就不能对此类型进行任何形式的推理。
因此,当您将类型约束更改为class
,它现在可以成功传递此方法 - 它可以推断出一个类型参数,但它现在成功地消除了此扩展方法。