Здравствуйте, Sinclair, Вы писали:
S>Ограничения, при которых можно безопасно использовать из сборки A сборку B после внесения в метаданные B изменений без перекомпиляции A, перечислить довольно сложно. S>И изменение сигнатуры конструктора в них явно не входит. S>Именно отсюда правило большого пальца: всегда перекомпилируем проект при изменении в любой из зависимостей.
По-моему, мы о разных вещах говорим. .Net позволяет UserAssembly инстанциировать класс из ChildAssembly, унаследованный от ParentAssembly, без ссылки UserAssembly->ParentAssembly.
S>Вот в вашем примере совершенно не нужно привлекать какую-то ParentAssembly. S>Достаточно просто иметь ChildAssembly с классом ChildClass, отнаследованным напрямую от object. S>Теперь мы заменяем сигнатуру конструктора в ChildClass c ChildClass(int x) на ChildClass(string x). S>Совершенно неважно, сгенерирован ли этот конструктор автоматически языком или вручную пользователем. Результат будет одинаковым — MethodNotFound.
Точно о разных вещах. ParentAssembly позволяет получить такую диаграмму зависимостей (references из метаданных):
Еще раз, прямой ссылки из UserAssembly на ParentAssembly нет, но это не мешает создавать класс, пронаследованный оттуда через ChildAssembly.
Реалистичный пример: ParentAssembly — внутренняя сборка продукта с внутренним функционалом. ChildAssembly — сборка с интерфейсами для плагинов. UserAssembly — плагин, не имеющий понятия о ParentAssembly.
Если разработчик продукта не хочет ломать обратную совместимость с UserAssembly, ему достаточно придерживаться простого правила: не менять/удалять ничего из ChildAssembly. Добавлять новые классы и интерфейсы — да. Менять/удалять — нет. Это легко соблюдать и легко проверять в процессе ревью. При этом, код внутри приватной ParentAssembly можно кромсать, как хочется — плагины на нее не ссылаются и изменения их не затронут.
Если мы добавляем сюда наследование конструкторов — получается, что поменяв конструктор в приватной ParentAssembly, мы неявно поменяли публичный интерфейс ChildAssembly, и сломали плагин. Ревью это не отловит, потому что исходники ChildAssembly мы не меняли.
На практике, ссылки из interface assemblies в private — это кривой паттерн, но текущая семантика его не ломает, а добавление наследования конструкторов — сломает. Или, выражаясь в Ваших терминах — это сделает нерекурсивное правило большого пальца рекурсивным.