Re[6]: есть
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.11.22 22:45
Оценка: 5 (1)
Здравствуйте, Quebecois, Вы писали:

Q>По-моему, мы о разных вещах говорим. .Net позволяет UserAssembly инстанциировать класс из ChildAssembly, унаследованный от ParentAssembly, без ссылки UserAssembly->ParentAssembly.

Нет, об одном и том же.
Ссылка на ParentAssembly тут ни при чём.

Q>Точно о разных вещах. ParentAssembly позволяет получить такую диаграмму зависимостей (references из метаданных):


Q>UserAssembly -> ChildAssembly

Q>ChildAssembly -> ParentAssembly

Q>Еще раз, прямой ссылки из UserAssembly на ParentAssembly нет, но это не мешает создавать класс, пронаследованный оттуда через ChildAssembly.

И это — совершенно неважно.

Q>Реалистичный пример: ParentAssembly — внутренняя сборка продукта с внутренним функционалом. ChildAssembly — сборка с интерфейсами для плагинов. UserAssembly — плагин, не имеющий понятия о ParentAssembly.

Q>Если разработчик продукта не хочет ломать обратную совместимость с UserAssembly, ему достаточно придерживаться простого правила: не менять/удалять ничего из ChildAssembly. Добавлять новые классы и интерфейсы — да. Менять/удалять — нет. Это легко соблюдать и легко проверять в процессе ревью. При этом, код внутри приватной ParentAssembly можно кромсать, как хочется — плагины на нее не ссылаются и изменения их не затронут.
Нет, это не так легко соблюдать в процессе ревью, как вам кажется.

Q>Если мы добавляем сюда наследование конструкторов — получается, что поменяв конструктор в приватной ParentAssembly, мы неявно поменяли публичный интерфейс ChildAssembly, и сломали плагин. Ревью это не отловит, потому что исходники ChildAssembly мы не меняли.

Наследование конструкторов ничего не меняет в сути проблемы. Повторю, на всякий случай, основное утверждение: любое изменение метаданных в зависимости требует перекомпиляции вашей сборки. В том числе и неявное.
То, что вы полагаете, что код ревью на уровне исходников ChildAssembly вас в этой ситуации спасёт — опасное заблуждение.
Q>На практике, ссылки из interface assemblies в private — это кривой паттерн, но текущая семантика его не ломает, а добавление наследования конструкторов — сломает. Или, выражаясь в Ваших терминах — это сделает нерекурсивное правило большого пальца рекурсивным.
Оно и так рекурсивно.
Смотрите:
ParentAssembly v1:
public class Parent
{
   public virtual void Foo() => Console.WriteLine("foo");
}


ChildAssembly:
public class Child: Parent
{
}


UserAssembly v1:
var c = new ChildClass();
c.Foo();

ParentAssembly v2:
public class Parent
{
   public void Foo(string x) => Console.WriteLine(x);
}


При запуске UserAssembly с ParentAssembly v2 вы получите MethodNotFound. Независимо от того, перекомпилируете ли вы ChildAssembly или нет. Несмотря на то, что исходный код ChildAssembly вовсе не менялся. И это вам ещё повезёт — потому, что вы, по крайней мере, заметите неладное.
Я могу вам накидать более тонких примеров, в которых будет вызываться не тот метод, которого вы ожидаете. Или тот метод, но с неверными аргументами.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.