.Net Inheritance - Автоматическая ссылка на зависимость поведения - PullRequest
7 голосов
/ 15 декабря 2010

Я столкнулся со странной проблемой, которую только что заметил.

Если у вас есть решение с 3 проектами

** ПРИМЕЧАНИЕ Редактируется после обсуждения **

Project LibA - имеет ClassA

namespace LibA
{
    public class ClassA
    {
        public override string ToString()
        {
            return "The logic in class A!";
        }
    }
}

Project LibB - имеет ClassB

using LibA;

namespace LibB
{
    public class ClassB
    {
        public ClassA a;

        public ClassB()
        {
            a = new ClassA();
        }

        public object Foo()
        {
            return a;
        }
    }
}

Project LibC - имеет ClassC

using LibB;

namespace LibC
{
    public class ClassC
    {
        public ClassB b;

        public ClassC()
        {
            b = new ClassB();
        }

        public object Foo()
        {
            return b.Foo();
        }
    }
}

Наконецтестовый драйвер

using System;
using LibC;

namespace Shell
{
    class Program
    {
        static void Main(string[] args)
        {
            ClassC c = new ClassC();
            Console.WriteLine(c.Foo());
        }
    }
}

Теперь, если вы скомпилируете это, все будет отлично работать.Если вы изучите содержимое бинарной папки LibC, то увидите, что она автоматически прокручивается через цепочку зависимостей, чтобы определить, что ей нужно использовать LibA и LibB

Однако, если вы измените ClassB для наследования от классаНапример, при попытке

using LibA;

namespace LibB
{
    public class ClassB : ClassA
    {
        ClassA a;
    }
}

при компиляции вы получите ошибку

Ошибка 2 Тип 'LibA.ClassA' определен в сборке, на которую нет ссылок.Вы должны добавить ссылку на сборку «LibA, версия = 1.0.0.0, Culture = нейтральный, PublicKeyToken = null».

** Оригинальный вопрос **

Кто-нибудь знает, почему (будь то msbuild или visual studio) он достаточно умен, чтобы ссылаться на LibA, когда ClassA является членом ClassB, но это не так?достаточно умен, чтобы ссылаться на LibA, когда ClassA является базовым классом ClassB?

Я знаю, что это непристойно, но я был бы очень признателен за некоторое последовательное поведение

** Исправленный вопрос с этими наблюдаемыми тестами **

Я слышу, что некоторые определяют как «прямые» или «косвенные» ссылки.Однако direct - это не просто область видимости, а наследование и фактическое использование типа.

Без наследования тестовый драйвер достаточно умен, чтобы разрешать и автоматически ссылаться на LibA, LibB и LibC.

Существует открытый член ClassA, видимый в ClassB, и все же это само по себе не приводит к ошибке компиляции / компоновки.

Отладчик определенно разрешает ClassA из тестового драйвера,так что он явно загрузил правильную сборку.

Так что с учетом всего этого.Теперь я получаю весь "прямой" и "косвенный" материал.

То, что мне до сих пор не понятно, почему компоновщик / компилятор / IDE по крайней мере не пытается автоматически ссылаться на зависимости ссылочнойбиблиотека в "прямом" сценарии?Он достаточно умен, чтобы знать, что зависимости существуют, и ссылаться на них в «косвенном» сценарии.

Ответы [ 3 ]

4 голосов
/ 15 декабря 2010

Это последовательное поведение.Первая - простая ссылка, вторая - наследование.

Если сборка скомпилирована, а класс наследуется от класса в другой сборке, эта ссылка необходима для его построения.

LibB содержит только информацию, которая добавлена ​​ в определении класса ClassB, она не копирует все из LibA (это приведет к несовместимому коду, если обновлено LibA и ClassA изменяется при этом, LibB будет по-прежнему содержать старую информацию).

Таким образом, чтобы использовать определение унаследованного класса в LibC, ему нужна информация из LibA (для ClassA) и LibB (ClassB) для его построения, поэтому необходима прямая ссылка на LibA.

В этом примере все ссылки на классы различных сборок являются частными, поэтому только следующий уровеньтребуется (ClassC не нужно знать о ClassA, так как нет прямого использования этого класса).Если бы использование ClassA в ClassB было публичным полем или пропетью, ClassC будет иметь прямую ссылку на ClassA и потребует также прямой ссылки на определение этого класса (ссылка на LibA из LibC).

В другой форме это также относится к примеру наследования.ClassC имеет прямую ссылку на ClassA (поскольку ClassB наследуется от ClassA), поэтому для создания полного определения класса необходима ссылка на объявленную сборку (а именно LibA).

0 голосов
/ 16 марта 2012

В первом сценарии вы просто используете ClassA . Таким образом, он не нуждается в ресурсе во время компиляции, просто во время выполнения.

Во втором сценарии вы наследуете от ClassA , поэтому его определение и информация необходимы компилятору для построения окончательной сборки.

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

Во втором сценарии VisualStudio не добавляет ссылку на проект , и это, я полагаю, ваше главное сомнение. Я предполагаю, что это так, чтобы избежать проблем, будучи навязчивым в вашем проекте. Но я просто догадываюсь ...

0 голосов
/ 15 декабря 2010

Я знаю, что это придирчиво, но я бы действительно ценю некоторые последовательные поведение

Он постоянен. Вы должны ссылаться на любой тип, который вы используете напрямую. Косвенные ссылки разрешаются прозрачно.

...