C# 为什么我需要引用我';我不直接使用?

C# 为什么我需要引用我';我不直接使用?,c#,inheritance,reference,C#,Inheritance,Reference,我有从外部开发人员那里收到的源代码,这些代码分为4种类型的项目:它们的框架、我的项目环境(我们称之为“ENV”)、应用程序库(称之为“库”)和应用程序本身(大约20个DLL,我统称为“应用程序”) 现在,我在这个混乱中添加了另一层,一个名为AdvanceFeatures的dll。它位于ENV的正下方(框架的顶部)。 这个dll只引用框架,而ENV引用它。 只有ENV使用此AdvanceFeatures dll,而Base和App仅使用ENV 我在这里的工作方式是,应用程序中的大多数对象都在Bas

我有从外部开发人员那里收到的源代码,这些代码分为4种类型的项目:它们的框架、我的项目环境(我们称之为“ENV”)、应用程序库(称之为“库”)和应用程序本身(大约20个DLL,我统称为“应用程序”)

现在,我在这个混乱中添加了另一层,一个名为AdvanceFeatures的dll。它位于ENV的正下方(框架的顶部)。 这个dll只引用框架,而ENV引用它。 只有ENV使用此AdvanceFeatures dll,而Base和App仅使用ENV

我在这里的工作方式是,应用程序中的大多数对象都在Base中定义,并在ENV中继承/实现类/接口。还有一小部分对象(在应用程序和基础中)从框架本身继承/实现类/接口(但这种情况非常罕见)

到目前为止,除了一个事实,一切都很好。编译器要求我从App中的每个dll和Base中添加对AdvanceFeatures dll的引用

我没有使用ENV之外的AdvanceFeatures,那么为什么需要这些引用呢

编辑:我已经为这个问题创建了一个演示项目。以下是项目详情:

Assembly: AdvanceFeatures
References: Nothing (Reference project-folder is empty)
Classes: Decorator, IEnvClass, IDecorator
IDecorator contents:
namespace AdvanceFeatures
{
    public interface IDecorator
    {
        IEnvClass Decorated { get; }
        void Decorate();
    }
}

IEnvClass contents: 
namespace AdvanceFeatures
{
    public interface IEnvClass
    {
        string Name { get; set; }
    }
}

Decorator contents:
namespace AdvanceFeatures
{
    public class Decorator : IDecorator
    {

        public Decorator(IEnvClass decorated)
        {
            Decorated = decorated;
        }

        #region Implementation of IDecorator

        public IEnvClass Decorated { get; set; }

        public void Decorate()
        {
            Decorated.Name = "NewName";
        }   

        #endregion
    }
}

Assembly: ENV
References: AdvanceFeatures (Compiled DLL)
Contents of only class SomeEnvClass:

namespace ENV
{
    public class SomeEnvClass : AdvanceFeatures.IEnvClass
    {
        public string Name { get; set; }
        private readonly AdvanceFeatures.IDecorator _decorator;

        public SomeEnvClass(string name)
        {
            Name = name;
            _decorator = new AdvanceFeatures.Decorator(this);
            _decorator.Decorate();
        }

        public string Foo()
        {
            return Name;
        }
    }
}


Assembly: TestBase
References: ENV (compiled DLL)
Contents of only class SomeEnvExtendingClass:

namespace TestBase
{
    public class SomeEnvExtandingClass : ENV.SomeEnvClass
    {
        public SomeEnvExtandingClass(string name) : base(name)
        {
        }
    }
}
我得到一个错误:

错误1在未引用的程序集中定义了类型“AdvanceFeatures.IEnvClass”。必须添加对程序集“AdvanceFeatures,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”的引用。E:\Projects\Dev\TestReferenceInheritance\TestBase\somevenextandingclass.cs 3 18 TestBase


现在,我知道了为什么DLL必须对编译后的可执行文件可用,但为什么开发人员要知道ENV的内部工作原理(更具体地说,它是继承树)以便扩展它?

基本上有两种可能性:

  • 您可能会使用AdvanceFeatures库的一部分而没有实现它,例如,在某个时刻获取对从AdvanceFeatures中的类继承的类的引用。这个类可能很小,例如,您可能在AdvanceFeatures中有一个enum,它由ENV中的方法返回
  • 你没有做过这样的事情,只是图书馆还需要在那里。除非将AdvanceFeature dll嵌入到ENV中,否则在没有AdvanceFeature的情况下,实际上无法使用ENV。通常这只是意味着它需要与可执行文件位于同一文件夹中。可能值得检查的是,您是否已将库设置为在其属性或对其属性的引用中复制本地等

  • 如果您在一个程序集中拥有

    public class Bar{
    ...
    }
    
    在另一个世界里

    public class Foo{
       public Bar MyBar{get;set;}
    }
    
    在第三种情况下

    public class FooBar{
        public Foo {get;set;}
    }
    
    然后你可以写:

    Bar myBar = new FooBar().Foo.MyBar;
    
    如果你没有告诉编译器关于bar的定义,那么它如何编译最后一行代码呢

    或者更直接地回答你的问题。使用引用其他程序集的程序集时,您的代码可能直接使用来自该其他程序集的内容,例如,如果在另一个程序集中声明了返回类型,或者当在另一个程序集中定义的类型的对象在方法的实现中使用或作为您直接引用的程序集中的私有字段时,间接使用了该程序集中的返回类型。编译器需要了解这些类型才能完成它的工作。它依赖于你告诉它在哪里可以找到这些类型的信息。即,添加引用

    编辑

    为了澄清一点,没有规则要求您引用与正在使用的dll相同的dll。您必须引用一个声明相同的dll。这就是为什么你可以签署一个dll。那么您就很高兴它总是相同的实现(或者至少是由有权访问密钥的人实现的)


    使用不同汇编程序的可能性在中间使用DLL对DLL/程序是必要的。您需要明确声明希望使用给定程序集的哪个实现。

    我阅读了所有答案和注释,因此我提出了这个示例。也许这更容易理解。:)

    Interfaces.dll

    public interface DoesntAcceptValidAndAccurateAnswersOrComments {
        bool ImAlwaysRight();
    }
    
    public class Neowizard : Interfaces.DoesntAcceptValidAndAccurateAnswersOrComments {
        public bool ImAlwaysRight() {
            return true;
        }
    }
    
    Classes.dll-引用Interfaces.dll

    public interface DoesntAcceptValidAndAccurateAnswersOrComments {
        bool ImAlwaysRight();
    }
    
    public class Neowizard : Interfaces.DoesntAcceptValidAndAccurateAnswersOrComments {
        public bool ImAlwaysRight() {
            return true;
        }
    }
    
    Program.exe-引用Classes.dll

    public class StackOverflowDotCom {
        public static void Main() {
            Neowizard someGuy = new Neowizard(); // CS0012
            someGuy.ImAlwaysRight();
        }
    }
    
    这一切都与编译器有关。当它试图编译Program.exe时,它会看到一个类型为Neowizard的对象。它还看到,它实现了一些名为DoesnCeptValidandAccurateAnswerSorComments的接口,但没有对Interfaces.dll的引用,它找不到它,因此它无法编译,因为就编译器而言,它是Program.exe不存在的接口

    由于Program.exe使用Neowizard,因此它还必须使用Neowizard派生的任何内容,而Neowizard恰好是该接口。这不仅仅适用于接口,与封装无关。这是C#编程语言的一条规则,由编译器强制执行


    如果你想更多地讨论这个问题,那么你应该向C#编译器团队中的某个人询问更多关于这个问题的信息,但请不要纠缠于每个试图帮助你解决问题的人的答案,因为他们的答案实际上是非常准确和受过良好教育的。

    ENV中的任何类型都会在AdvanceFeatures中派生类型吗?是的。这有什么关系?(我的问题是,我不明白为什么ENV的实现需要在APP或Base中引用)因为如果程序集a中有一个类型P,并且程序集B中有一个扩展了P的类型Q,那么在不引用a的情况下就不能使用B中的Q,因为没有基类型的定义,该类型是不完整的。给出特定的编译器输出将帮助我们确定到底是什么导致了它需要引用。继承与封装相反(在C语言中至少,例如C++可以是不同的)。继承是公共的,因此没有封装。编译器确实需要这些知识。编译器如何知道