Создание динамического фальшивого класса внутри сборки

Возможно, то, что я спрашиваю, невозможно, но, тем не менее, вот моя проблема и вопрос. Прежде всего это C# и.NET.
Я хотел бы определить пустую реализацию (пустые методы, функции, возвращающие значения по умолчанию) класса для интерфейса таким образом, если я изменю интерфейс, мне не нужно будет адаптировать код. К сожалению, я не могу сгенерировать реализацию, содержащую сборку, и не могу определить динамический макет для нее, потому что создание экземпляров выполняется автоматически посредством отражения. Вот проблема, объясненная более широко:

У меня есть DLL / сборка, давайте назовем его IMyInterface.dll, который содержит интерфейс: IMyInterface.
Слои выше у меня есть реализация в отдельной dll / сборке, назовем ее MyInterfaceImplementation.dll.
Посередине / между ними у меня есть автоматизированная среда тестирования, которая может зависеть от IMyInterface.dll, но не от MyInterfaceImplementation.dll.
Теперь эта среда тестирования использует инфраструктуру производственного кода, которая создает экземпляры типов посредством отражения. Это структура типа внедрения зависимости. Итак, вы говорите инфраструктуре производственного кода, дайте мне эту реализацию интерфейса из этой сборки.
В нашем случае вы говорите, дайте мне IMyInterface из MyInterfaceImplementation.dll. В тестовой среде вы не можете зависеть от MyInterfaceImplementation, поэтому вы определяете класс fake/stub/mock на основе IMyInterface в третьей сборке, позволяющей вызывать его: MyInterfaceFakeImplementation.dll
В рамках теста вы говорите, дайте мне IMyInterface из MyInterfaceFakeImplementation.dll, и все в порядке.
Примечание. В иерархии наших модулей невозможно реструктурировать зависимости. Что касается Mock Frameworks, я не контролирую реализацию. Инстанцирование выполняется внутри структуры внедрения зависимостей.

Когда вы пишете свой код в MyInterfaceFakeImplementation.dll, вы записываете так:

class MyInterfaceFakeImplementation : IMyInterface 
{
  // IMyInterface implementation. 
}

Теперь я хотел бы предоставить динамический класс IMyInterface, поэтому при изменении интерфейса мне не нужно адаптировать фальшивку.

Очень коротко, вот что я хочу:

Дано:
Интерфейс IMyInterface в IMyInterface.dll
MyInterfaceFakeImplementation имплементация IMyInterface в MyInterfaceFakeImplementation.dll
MyInterfaceFakeImplementation имеет пустые функции и возвращает значения по умолчанию.

Когда:
Я изменяю IMyInterface (например, меняю сигнатуру функции).

Затем:
Мне не нужно менять MyInterfaceFakeImplementation, просто перекомпилируйте MyInterfaceFakeImplementation.dll. Примечание. Невозможно сгенерировать эту сборку, ее необходимо скомпилировать.

Вот обходной путь.
Сделайте фальшивую реализацию (класс) рядом с IMyInterface в IMyInterface.dll, давайте назовем его MyInterfaceFakeBase. В MyInterfaceFakeImplementation.dll извлеките MyInterfaceFakeImplementation из этого базового класса MyInterfaceFakeBase и оставьте его пустым. При изменении интерфейса (IMyInterface) адаптируйте MyInterfaceFakeBase и никогда не беспокойтесь о MyInterfaceFakeImplementation и MyInterfaceFakeImplementation.dll.

Хорошо, для тех, кто хотел бы начать кодирование, вот пример приложения типа Console, которое может помочь. Добавьте класс к этому коду, чтобы он нашел тип, реализующий интерфейс, и если вы измените интерфейс, вам не нужно менять этот класс. (Не изменяйте основную функцию.)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace DynamicFake3
{
    public interface IMyInterface
    {
        void SimpleMethod();
        bool SimpleFunction();
        void OneParameterMethod(int i);
    }

    class Program
    {
        static void Main(string[] args)
        {

            Assembly anAssembly = Assembly.LoadFrom("DynamicFake3.exe");

            foreach (Type aType in anAssembly.GetTypes())
            {
                if (aType.GetInterfaces().Contains(typeof(IMyInterface)))
                {
                    Console.WriteLine(aType.FullName);
                }
            }
        }
    }
}

Пока Ласло

2 ответа

Решение

Ну, никто не ответил на это, поэтому невозможно сделать что-то подобное. Можно создать динамический декоратор или прокси или макет для интерфейса во время выполнения или создать сборку, которая имеет поддельную реализацию для интерфейса, но не так, как мне бы этого хотелось. C#, .NET, CLR не позволяет этого. Или лучше сказать, что это хорошо, что C# не допускает такого динамического (интерпретируемого) поведения.

Вы можете использовать переадресацию типов для объявления типа, перемещенного в сборку, создаваемую во время выполнения (см. Assemblybuilder), где вы можете создать свой тип (см. Typebuilder)

Другие вопросы по тегам