代码之家  ›  专栏  ›  技术社区  ›  Greg

为什么使用库A的C客户机需要库B的using语句(A使用)

  •  1
  • Greg  · 技术社区  · 15 年前

    我有:

    • 主程序类-使用库A
    • 库A-具有部分类,这些类混合了来自库B的方法
    • 库B-混合方法和接口

    所以在库B中,当我包含一个实现i node的部分节点类(在库B中定义)时,我突然在我的主类中得到一个错误,它使用库A中的节点。错误告诉我,在主类中,我必须有一个到库B的using语句。

    有什么想法吗?

    编辑-代码除外

        // *** PROGRAM ***
        class Program
        {
            static void Main(string[] args)
            {
                var context = new Model1Container();
                Node myNode;  // ** WITHOUT A using for Library B I have an error here ***
             }
         }
    
    
    // ** 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-澄清是引用还是使用错误:

    因此,“node mynode;”行出现的错误是:

    错误1类型 'topology.inode'1'是在中定义的 未引用的程序集。 必须添加对程序集的引用 '拓扑,版本=1.0.0.0, 文化=中性, publicKeyToken=空。U:我的 dropbox\source\toplogylibrary\topologidal_consoletest\program.cs 11 13 topologidal_consoletest

    当我让vs为我修复它时,它添加了库2作为参考。也就是说,在客户机代码之前或之后都没有“使用”。所以这个问题是一个参考而不是使用问题。

    编辑3-不是关于这个问题,但是我现在注意到在程序项目中,我不能看到混合方法(从库B),除非我有一个到库B的using语句?关于这个问题,我可能会提出一个单独的问题。

    6 回复  |  直到 10 年前
        1
  •  5
  •   Igor Zevaka    15 年前

    我对正在发生的事情的理解是,您只引用来自主程序和编译器的库A,它告诉您添加对库B的引用,因为库A公开的某些类型是在库B中定义的。

    要解决此问题,请将对库B的引用添加到主程序项目中。

    这是一个小图表。如果库A公开了在库B中定义的类型,那么main也必须引用库B。以下情况不起作用:

    _____________             _____________               _____________
    | Main       |references  | Library A  |references    | Library B  |
    |           -|------------|->         -|--------------|->          |
    |            |            | public     |              | SomeType   |
    |            |            |  SomeType  |              |            |
    |            |            |            |              |            |
    -------------             -------------               -------------
    

    仅当通过库A可以访问库B中定义的类型时,此问题才会出现。这将出现在以下情况之一:

    • 编辑 在库A中定义的类型( Node )从库B中的类型派生( INode<int> )
    • 在库A中定义的方法使用库B中的类型作为返回类型或参数。
    • 在库A中定义的类型将库B中的类型公开为属性或公共字段。

    您需要从assembly1添加对assembly3的引用,以使其编译。

    _____________             _____________               _____________
    | Main       |references  | Library A  |references    | Library B  |
    |           -|------------|->         -|--------------|->          |
    |            |            | public     |              | SomeType   |
    |            |references  |  SomeType  |              |            |
    |           -|------------|------------|--------------|->          |
    |            |            |            |              |            |
    -------------             -------------               -------------
    
        2
  •  5
  •   Jay    15 年前

    如果librarya公开属性,从方法返回对象,或者接受libraryb中定义的类型的参数,并且在其中一个类型的主程序中声明或使用变量,则需要using语句。

        3
  •  1
  •   Jeff Schumacher    15 年前

    由于库A使用的是来自库B的混合方法和接口,如果库A和库B存在于不同的命名空间中,则需要一个using语句,这就是C的工作方式。编译器需要知道在哪里可以找到库A中使用的库B类型。

        4
  •  0
  •   John Saunders    15 年前

    你所用的只是 Node 从图书馆A上的课,没错。但是,定义的一部分 结点 类是它实现 INode<int> 来自库B的接口。

    存在的事实 结点 类要求您包含对库B的引用。

        5
  •  0
  •   Peter Duniho    10 年前

    正如其他答案已经正确解释的那样,您的主程序需要引用库B,因为库A通过自己的公共API公开了库B类型。即。 Node 公开实施 INode<T> 使该类型对主程序可见。

    通常,正确的解决方案只是将库B的引用添加到主程序中。毕竟,主程序在运行时当然需要库B,即使它本身不直接访问该库中声明的任何类型。

    但是,如果出于某种原因添加引用有问题,假设您至少可以更改库A,则还有一种替代方法。即封装库B中类型的使用,以便 对使用库A的代码可见。通常,这种封装将涉及某种代理或包装,以隐藏对第三个库的使用,并(在某些情况下)将第三个库的功能公开给引用第二个库的程序集。

    例如,可以将库A更改为如下所示:

    namespace TopologyDAL
    {
        public partial class Node
        {
            // Auto generated from EF
        }
    
        public partial class Node
        {
            public int Key { ... }
    
            private class NodeProxy : INode<int>
            {
                private readonly Node _node;
    
                public NodeProxy(Node node)
                {
                    _node = node;
                }
    
                public int Key { get { return _node.Key; } }
            }
    
            private readonly NodeProxy _nodeProxy;
    
            public Node()
            {
                _nodeProxy = new NodeProxy(this);
            }
        }
    }
    

    然后,只要您想使用库B中的扩展方法,就可以使用 _nodeProxy 成员而不是 this .

    当然,上面假定主程序实际上没有直接使用库B中的任何内容,并且库B中类型的所有用法都只在库A中找到,甚至在返回值、属性类型等方面都没有从库A中暴露出来,但是如果不是这样呢?例如,如果您希望主程序在不引用库的情况下从库B访问扩展方法,该怎么办?

    好吧,我的第一个回答是,“去吧,已经参考了大会!”:)但是为了争论,我们假设你因为某种原因不能这样做,或者这样做至少很不方便。然后,您可以扩展代理方法,将代理方法添加到您的库A类型中,然后再将代理方法委托给库B中的实现。

    例如,扩展上面的内容,可以添加到 结点 类声明其他方法:

    public void FromNodeMixin()
    {
        _nodeProxy.FromNodeMixin();
    }
    

    请注意,该方法本身不添加库B的公共用法。相反,它使用(先前解释的)代理实例将调用委托给库B中声明的扩展方法。这样,只有库A实际需要引用库B;主程序可以引用库A而不暴露于库B因此不需要显式引用。


    我要重申的是 事实上,价值在于 解决这个问题。首先,添加代理可能很耗时。对于一两种类型的人来说,这是很好的,可能有几种方法。但是,如果你试图隐藏每一个间接使用的DLL,否则你将使用大量的特性,那么它将很快变得非常老。

    正如我之前提到的,不必添加对库B的引用当然并不意味着库B不需要 目前 让程序运行。您仍然需要将库放在那里,这样当库A调用它时,就可以使用它。拥有主程序引用库B是我所知道的确保库B被复制到构建输出目录以确保DLL存在的最简单方法之一。

        6
  •  -1
  •   Coding Flow    15 年前

    C中的分部类只是存在于多个文件中的类。不能有两个文件在不同的命名空间中定义分部类。