Загружать разные версии одной и той же DLL с зависимостями, которые также отличаются? - PullRequest
0 голосов
/ 18 мая 2018

Представьте себе сценарий, A.dll и B.dll, A.dll ссылаются на B.dll и вызывают методы, которые находятся в B.dll.

В какой-то момент в будущем у вас появятся две разные версииA.dll и B.dll (не важно, почему это так).Вы хотите иметь возможность использовать обе версии этих dll в одном приложении.

Проблема, с которой я столкнулся, заключается в том, что я могу загрузить Av1.dll и Av2.dll, но обе они в конечном итоге используют Bv1..dll.

Итак, что я хочу, это:

Av1.dll --> Bv1.dll
Av2.dll --> Bv2.dll

Но, как я говорю, я получаю следующее:

Av1.dll --> Bv1.dll
Av2.dll --> Bv1.dll

Домены приложений на самом деле не жизнеспособны, так как они заканчиваютсяЭто громоздко из-за каждого ввода и вывода, необходимого для реализации MarshalByRefObject.

Я открыт для творческих решений, даже если они немного странные.Это в большей степени академический вопрос, так что не увязайте только в рефакторинге DLL или какой-нибудь выдумки, которую вам нужно сделать в реальном мире, рассматривайте это как вызов.

Возможно ли это?Как и вы могли бы динамически проверять, переписывать и перекомпилировать DLL-файлы за кулисами, но заменяя ссылки, чтобы дать, по сути:

A.dll --> B.dll
C.dll --> D.dll

Как я уже сказал, я открыт для творческих решений.

Редактировать

Хорошо, возможно, поможет более ясный пример.

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

Итак, при нормальных обстоятельствах у вас будет:

TaxHelper helper = new TaxHelper();
var result = helper.CalculateIncomeTax(...params...);

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

Так что я экспериментировал с чем-то вроде этого (это просто не в моем вкусе).голова между прочим, поэтому может быть не на 100% правильно):

Assembly taxHelper1Assembly = Assembly.LoadFrom(...path1...);
Assembly taxHelper2Assembly = Assembly.LoadFrom(...path2...);

Type taxHelper1Type = taxHelper1Assembly.GetType(...);
Type taxHelper2Type = taxHelper2Assembly.GetType(...);

dynamic taxHelper1 = Activator.CreateInstance(taxHelper1Type);
dynamic taxHelper2 = Activator.CreateInstance(taxHelper2Type);

var result1 = taxHelper1.CalculateIncomeTax(...params...);
var result2 = taxHelper2.CalculateIncomeTax(...params...);

Теперь это работает, вплоть до определенного момента, taxHelper1 и taxHelper2 - это разные версии и будут давать разные результаты ... однако.... хотя классы TaxHelper верхнего уровня отличаются, внутренне, где они ссылаются на другие dll как зависимости, taxHelper1 ссылается на правильные зависимости, потому что они были загружены первыми, taxHelper2 ТАКЖЕ ссылается на taxHelper1 зависимости.

Редактировать 2

Думаю, я нашел ответ в этой теме: Загрузка зависимых сборок вручную

1 Ответ

0 голосов
/ 18 мая 2018

Здесь этого может быть достаточно, чтобы вы начали.Это называется внедрение зависимости, как кто-то упоминал в комментариях под вашим вопросом.Вы должны прочитать об этом.

Здесь я определяю два типа в моем A.dll.Одним из них является интерфейс, который определяет контракт для B:

public interface IDependencyB
{
    string Name { get; }
}

А вот мой класс A.В его конструкторе требуется IDependencyB:

public class A
{
    public A(IDependencyB dependencyB)
    {
        System.Diagnostics.Debug.Print(dependencyB.Name);
    }
}

Затем вы можете определить два (или сколько угодно) вариантов классов в отдельных сборках, если хотите, которые реализуют этот интерфейс:

class B1 : IDependencyB
{
    public string Name => "B1";
}

class B2 : IDependencyB
{
    public string Name => "B2";
}

Вы можете проверить это так:

var b1 = new B1();
var b2 = new B2();
var a1 = new A(b1);
var a2 = new A(b2);

Это довольно простой пример, но я думаю, он должен направить вас в правильном направлении.

...