为什么我需要使用Libary B extn方法的使用声明,如果它们用于图书馆A&这是我的客户使用的图书馆吗?

时间:2010-05-21 02:15:35

标签: c# .net assemblies extension-methods

我有:

  • 主程序类 - 使用库A
  • 图书馆A - 有部分类,混合了图书馆B的方法
  • 图书馆B - 混合方法&接口

为什么我需要在LibaryB中使用using语句才能让他们的扩展方法在主类中工作?这是因为它是库B,它定义了将被扩展的类。

编辑 - 代码

除外
    // *** PROGRAM ***
    using TopologyDAL;
    using Topology;  // *** THIS WAS NEEDED TO GET EXTN METHODS APPEARING ***
    class Program
    {
        static void Main(string[] args)
        {
            var context = new Model1Container();
            Node myNode;  // ** trying to get myNode mixin methods to appear seems to need using line to point to Library B ***
         }
     }


// ** LIBRARY A
namespace TopologyDAL
{
    public partial class Node
    {
        // Auto generated from EF
    }

    public partial class Node : INode<int>   // to add extension methods from Library B
    {
        public int Key
    }
}

// ** LIBRARY B
namespace ToplogyLibrary
{
    public static class NodeExtns
    {
        public static void FromNodeMixin<T>(this INode<T> node) {
           // XXXX
        }
    }
    public interface INode<T> 
    {
        // Properties
        T Key { get; }

        // Methods
    }

}

2 个答案:

答案 0 :(得分:3)

扩展方法仅在您导入定义的命名空间时才可用。

否则,编译器需要针对每个引用的库中的每个扩展方法进行解析,这会减慢编译时间。
此外,如果不同的命名空间包含具有相同签名的扩展方法,则无法使用扩展方法。

总之,扩展方法本身就是功能,需要导入其命名空间;它们不会自动导入它们扩展的类的命名空间。

答案 1 :(得分:2)

这是扩展方法的一个令人遗憾的可发现性问题。为了使它们可用,您需要为包含具有扩展的静态类的命名空间添加using语句。查看此blog有关扩展方法的信息。

以下是关于扩展方法的some background

  

那么编译器如何知道哪个   扩展方法绑定?编译器   寻找扩展方法   调用时最内层的命名空间   为扩展方法,然后在   由...导入的所有命名空间   “使用”条款。这个过程是   然后向外移动直到我们到达   最顶层的命名空间。

     

因为扩展方法可以   导入到当前上下文中   “使用”子句并绑定到任何   可分配的对象(见   兑换部分详情)   实例参数,各种各样的   有趣的可能性开放   扩展a实现的方法   类型。这可以简单地完成   导入扩展库   方法并使用这些方法,如果   他们被宣布为你的类型   不拥有。这意味着

     
      
  1. 根据您导入的库,可以使代码做不同的操作   的东西。

  2.   
  3. 客户端获得了一种扩展他不拥有的类型的有趣方式。

  4.   

我的理解是使用扩展方法就像使用任何其他类型一样,除了你不能限定它们(这在语法上是不可能的),因此需要using语句。由于您可以在不同的名称空间中的不同类中定义它们中的多个,因此编译器需要一种方法来解决歧义。

我设想将来在Visual Studio中添加一个功能,以便在键入方法名称时导入正确的命名空间,其方式类似于类和接口名称。

考虑这种情况:

namespace FruityNamespace {
  public static class FruityExtensions {
    public static string ToFunString(this int value) {return value + " bananas"; }
  }
}

namespace VegetablNamespace {
  public static class VegetablyExtensions {
    public static string ToFunString(this int value) {return value + " carrots"; }
  }
}

//In some other source file
static void Main(/**/) {
  int things = 3;
  3.ToFunString(); //error CS1061: 'System.Int' does not contain a definition for 'ToFunString' and no extension method 'ToFunString' accepting a first argument of type 'System.Int' could be found (are you missing a using directive or an assembly reference?)
}

要使用任何这些扩展方法,您需要导入正确的命名空间:

using FruityNamespace;
//OR
using VegetablyNamespace;

您可能会问到导入两个命名空间时会发生什么。你得到一个编译器错误:

error CS0121: The call is ambiguous between the following methods or properties: 'VegetablNamespace.VegetablyExtensions.ToFunString(int)' and 'FruityNamespace.FruityExtensions.ToFunString(int)'