Зачем мне ссылаться на DLL, который я не использую напрямую? - PullRequest
7 голосов
/ 31 августа 2011

У меня есть исходный код, полученный от внешнего разработчика, этот код разделен на 4 типа проектов: их структура, среда для моего проекта (назовем его «ENV»), база приложения (назовите его «Base») ") и само приложение (около 20 dll я в совокупности назову" Приложение ").

Теперь я добавил еще один слой к этому беспорядку, dll с именем AdvanceFeatures. Он лежит прямо под ENV (сверху каркаса). Эта dll ссылается только на структуру, и ENV ссылается на нее. Только ENV использует эту DLL AdvanceFeatures, в то время как Base и App используют только ENV.

То, как я здесь работаю, заключается в том, что большинство объектов в приложении определены в Base и наследуют / реализуют классы / интерфейсы в ENV. Также небольшая часть этих объектов (в App и Base) наследует / реализует классы / интерфейсы от самой платформы (но это довольно редко).

Пока все хорошо, кроме одного факта. Компилятор требует, чтобы я добавил ссылку на DLL-файл AdvanceFeatures из каждой библиотеки DLL в приложении и из Base.

Я не использую AdvanceFeatures за пределами ENV, так зачем нужны эти ссылки?

Редактировать: Я создал демонстрационный проект для этой проблемы. Это детали проекта:

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, версия = 1.0.0.0, культура = нейтральная, PublicKeyToken = ноль». E: \ Projects \ Dev \ TestReferenceInheritance \ TestBase \ SomeEnvExtandingClass.cs 3 18 TestBase

Теперь я знаю, почему DLL должна быть доступна для скомпилированного исполняемого файла, но почему разработчик должен знать внутреннюю работу ENV (точнее, это дерево наследования) для его расширения?

Ответы [ 3 ]

10 голосов
/ 02 сентября 2011

Я прочитал все ответы и комментарии, поэтому придумал этот пример.Может быть, это немного легче понять.:)

Interfaces.dll

public interface DoesntAcceptValidAndAccurateAnswersOrComments {
    bool ImAlwaysRight();
}

Classes.dll - Ссылки Interfaces.dll

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.Что он также видит, так это то, что он реализует некоторый интерфейс с именем DoesntAcceptValidAndAccurateAnswersOrComments, но без ссылки на Interfaces.dll он не может его найти, поэтому он не может компилироваться, потому что это интерфейс, который с точки зрения компилятора не существует для Program.EXE.

Поскольку Program.exe использует Neowizard, он также должен использовать все, что происходит от Neowizard, - это интерфейс.Это относится не только к интерфейсам, но и не связано с инкапсуляцией.Это правило языка программирования C #, которое применяется компилятором.

Если вы хотите больше аргументировать ситуацию, вам следует попросить кого-нибудь из команды разработчиков C # подробнее об этом, но, пожалуйста, прекратите преследоватьответ каждого, кто пытался помочь вам с вашим вопросом, когда его ответы на самом деле достаточно точны и хорошо образованы.

4 голосов
/ 31 августа 2011

Если у вас в одной сборке есть

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, как он сможет скомпилировать последнюю строку кода?

или ответить на ваш вопрос более прямо. При использовании сборки, которая ссылается на другую сборку, существует вероятность того, что ваш код может использовать материал из этой другой сборки напрямую, например. если возвращаемый тип объявлен в другой сборке или косвенно, когда объекты типов, определенные в другой сборке, используются в реализации методов или как частные поля в сборке, на которую вы ссылаетесь напрямую. Компилятор должен знать об этих типах, чтобы он работал. Он полагается на вас, чтобы сообщить ему, где он может найти информацию этих типов. То есть добавить ссылку

EDIT

Чтобы пояснить немного, нет правила, требующего от вас ссылаться на ту же DLL, что и используемая вами dll. Вы должны ссылаться на DLL, которая говорит, что это то же самое. Вот почему вы можете подписать DLL. Тогда вы гарантируете, что это всегда одна и та же реализация (или, по крайней мере, сделанная кем-то, имеющим доступ к ключу)

возможность использовать другую сборку, однако для dll / программы предусмотрены требования, использующие dll в середине. Вам необходимо явно указать, какую реализацию данной сборки вы хотите использовать.

1 голос
/ 31 августа 2011

По сути, существует две возможности:

  1. Вы можете использовать часть библиотеки AdvanceFeatures, не осознавая этого, например, в какой-то момент получить ссылку на класс, который наследуется от класса в AdvanceFeatures.Этот класс может быть крошечным, у вас может быть перечисление в AdvanceFeatures, которое возвращается методом, например, в ENV.
  2. Вы не сделали ничего подобного, и это просто тот факт, что библиотека все еще должна бытьтам.Если вы не внедрите dll AdvanceFeature в ENV, вы на самом деле не сможете использовать ENV без наличия AdvanceFeature.Обычно это просто означает, что он должен находиться в той же папке, что и ваш исполняемый файл.Возможно, стоит проверить, установлены ли у вас библиотеки для копирования локальных и т. Д. В их свойствах или ссылки на их свойства.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...