混合通用方法和扩展方法

我在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。
  • 键入约束某些其他库LB2中定义的某种类型的泛型方法。
  • 定义TP1中的另一种方法。
  • 现在在你的库中只引用LB1并尝试调用类型TP1的第二种方法
  • 如果您不使用TP1但在LB1中定义了其他类型,则不会收到错误。 此外,即使TP1类型的方法之一需要LB2中定义的类型的参数(并且您不调用此方法),它也不会产生此错误


    当一个程序集依赖于另一个程序集时,第一个程序集也依赖于另一个程序集的所有依赖关系 - 不管使用什么。 程序集依赖关系有效地解耦,编译后可以部署另一个程序集版本,编译器无法知道在这种情况下,第一个程序集不会使用第二个程序集中的一个或多个依赖关系。

    要解决这个问题,你可以简单地添加一个对WindowsBase的引用。

    或者,正如prashanth指出的那样,将SomeExtMethod放入不同的程序SomeExtMethod以便使用该程序的代码不需要依赖WindowsBase。

    更新:如果您不使用程序集中的任何内容,则不需要任何依赖关系。 但是,只要使用一个程序集,就需要该程序集的所有依赖关系。 这在Visual Studio添加引用的方式中很明显。 如果您添加对程序集的引用,它会将所有相关程序集(未在GAC中注册)复制到您添加的程序集的调试/版本目录中。

    更新:至于编译错误:这是写它的方式 - 可能没有其他原因。 如果不引用相关程序集,是否会收到编译错误是个好主意? 也许,你可能会使用引用中的某些东西,并且可能会直接从引用引用中使用某些东西 - 编译错误比部署错误更好。

    为什么不对每个未引用的辅助依赖项编译错误? 再次,它是这样写的。 也许这里的一个错误也是好的; 但这将是一个突破性的变化,需要真正有说服力的理由。


    我不确定这可以由编译器团队以外的人解答。 我现在认为这是与类型推理有关 - 但是§7.6.5.1方法调用谈论了推理,§7.6.5.2扩展方法调用在这个问题上保持沉默 - 尽管事实上推理显然确实发生在搜索适用的扩展方法。

    我认为它正在尝试某种形式的推理,然后才会对标识符进行比较(这会因为名称错误而立即排除扩展方法)。 显然,如果它无法理解类型约束,它就不能对此类型进行任何形式的推理。

    因此,当您将类型约束更改为class ,它现在可以成功传递此方法 - 它可以推断出一个类型参数,但它现在成功地消除了此扩展方法。

    链接地址: http://www.djcxy.com/p/96949.html

    上一篇: Mixing generic methods and extension methods

    下一篇: Generic generic extension method (sic!)