开发者

Why do I need to reference a dll which I'm not using directly?

I have source code I received from an external developer, this code is divided up into 4 types of projects: Their framework, the environment for my project (lets call it "ENV"), the application base (call it "Base") and the application itself (about 20 dlls I'll collectively call "App").

Now, I've added another layer to this mess, a dll by the name AdvanceFeatures. It lays right under the ENV (on top of the framework). This dll references nothing but the framework, and the ENV references it. Only the ENV makes use of this AdvanceFeatures dll, while Base and App use the only the ENV.

The way I'm working here is most objects in the App are defined in Base and inherit/implement classes/interfaces in ENV. Also a small part of those objects (in App and Base) inherit/implement classes/interfaces from the framework itself (but this is quite rare).

So far all is well, apart from one fact. The compiler demands I'll add a reference to the AdvanceFeatures dll from each one of the dlls in App, and from Base.

I don't make any use of AdvanceFeatures outside of ENV, so why is these references needed?

Edit: I've created a demo project for this problem. This is the project details:

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 cla开发者_如何学编程ss 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)
        {
        }
    }
}

I get the error:

Error 1 The type 'AdvanceFeatures.IEnvClass' is defined in an assembly that is not referenced. You must add a reference to assembly 'AdvanceFeatures, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. E:\Projects\Dev\TestReferenceInheritance\TestBase\SomeEnvExtandingClass.cs 3 18 TestBase

Now, I know why the DLL must be made available to the compiled executable, but why should the developer know the inner workings of ENV (more specifically, it's inheritance tree) in order to extend it?


I read all the answers and comments so I came up with this example. Maybe it is a bit easier to understand. :)

Interfaces.dll

public interface DoesntAcceptValidAndAccurateAnswersOrComments {
    bool ImAlwaysRight();
}

Classes.dll - References Interfaces.dll

public class Neowizard : Interfaces.DoesntAcceptValidAndAccurateAnswersOrComments {
    public bool ImAlwaysRight() {
        return true;
    }
}

Program.exe - References Classes.dll

public class StackOverflowDotCom {
    public static void Main() {
        Neowizard someGuy = new Neowizard(); // CS0012
        someGuy.ImAlwaysRight();
    }
}

This has everything to do with the compiler. When it tries to compile Program.exe, it sees an object of type Neowizard. What it also sees is that it implements some interface called DoesntAcceptValidAndAccurateAnswersOrComments, but without a reference to Interfaces.dll it cannot find it, thus it cannot compile because it is an interface that as far as the compiler is concerned, does not exist to Program.exe.

Because Program.exe uses Neowizard, it must also use anything Neowizard derives from, which happens to be the interface. This does not just apply to interfaces, and has zero to do with encapsulation. This a rule of the C# Programming Language that is enforced by the compiler.

If you want to argue the case more, then you should go ask someone on the C# Compiler Team more about it, but please quit dogging on everyone's answer who has tried to help you with your question when their answers are actually quite accurate and well educated.


If you in one assembly have

public class Bar{
...
}

and in another have

public class Foo{
   public Bar MyBar{get;set;}
}

and in a third have

public class FooBar{
    public Foo {get;set;}
}

then you could write:

Bar myBar = new FooBar().Foo.MyBar;

if you haven't told the compiler about the definition of bar how would it be able to compile the last line of code?

or to answer your question more directly. When using an assembly that references another assembly, there's the possibility that your code might be using stuff from that other assembly directly E.g. if a return type is declared in the other assembly or indirectly when objects of types defined in the other assembly is used in the implementation of methods or as private fields in the assembly you are referencing directly. The compiler need to know about these types to do it's work. It relies on you to tell it where it can find the information of those types. I.e. add the reference

EDIT

To clarify a bit there's no rule requiring you to reference the same dll as the dll you are using is using. You have to reference a dll that says it's the same. That's why you can sign a dll. Then you are gauranteed it's always the same implementation (or at least made by some one with access to the key)

the possibility of using a different assembly however enforces are requirement on the dll/program using the dll in the middle. You need to explicitly declare which implementation of a given assembly you wish to use.


There are essentially two possibilities:

  1. You might use part of the AdvanceFeatures library without realising it, for example at some point getting a reference to a class which inherits from a class in AdvanceFeatures. This class might be tiny, you might have an enum in AdvanceFeatures which gets returned by a method in ENV for example.
  2. You haven't done anything like this and it's just the fact that the library still needs to be there. Unless you embed the AdvanceFeature dll inside ENV you won't actually be able to use ENV without AdvanceFeature being around somewhere. Usually that just means it needs to be in the same folder as your executable. It may be worth checking you have the libraries set to copy local etc. in their properties, or the references to their properties.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜