Как создать динамический тип, производный от закрытого универсального типа - PullRequest
1 голос
/ 08 ноября 2011

Я пытаюсь динамически объединить любое количество типов в новый тип, который наследует все эти типы. На данный момент это должно работать только для интерфейсов.

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

Итак, в основном у меня есть класс (TypeBuilder - см. Код ниже), который может создавать эти типы. Это работает довольно хорошо для «простых» типов. Но я хочу иметь возможность передавать закрытые универсальные типы. При попытке сделать это с моей текущей реализацией выдается TypeLoadException, когда я пытаюсь создать динамический тип (через TypeBuilder.CreateType).

Должен ли я сказать TypeBuilder, что новый тип является универсальным типом, хотя он наследуется только от закрытых универсальных типов? Если да, как я могу это сделать?

Вот как я это использую:

MultiTypeBuilder multiTypeBuilder = 
    new MultiTypeBuilder(Guid.NewGuid().ToString());   

multiTypeBuilder.SetBaseType(typeof(IFoo));
multiTypeBuilder.SetBaseType(typeof(IBar<IFoo>));
multiTypeBuilder.SetBaseType(typeof(IBaz));

Type multiType = multiTypeBuilder.CreateType();

Это моя текущая реализация (немного упрощенная):

private class MultiTypeBuilder
{
    private readonly TypeBuilder m_TypeBuilder;

    public MultiTypeBuilder(string name)
    {
        ModuleBuilder multiTypeModule = GetMultiTypeModule();

        TypeAttributes attributes = TypeAttributes.Interface | TypeAttributes.SpecialName | TypeAttributes.Abstract | TypeAttributes.Public;

        m_TypeBuilder = multiTypeModule.DefineType(name, attributes);
    }

    public void SetBaseType(Type baseType)
    {
        m_TypeBuilder.AddInterfaceImplementation(baseType);
    }

    public Type CreateType()
    {
        return m_TypeBuilder.CreateType();
    }

    private static ModuleBuilder GetMultiTypeModule()
    {
        AssemblyName assemblyName = new AssemblyName(c_DynamicAssemblyName);
        AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
        return assemblyBuilder.DefineDynamicModule("MultiTypeAssembly");
    }
}

Спасибо за вашу поддержку!

Ответы [ 2 ]

1 голос
/ 09 ноября 2011

Позор мне.

Как сказал VirtualBlackFox, мой слегка сжатый пример работает. В моем «реальном» коде я создаю имя динамического типа, комбинируя FullNames типов, которые должны быть объединены. Это, очевидно, приводит к недопустимому типу имени при использовании с универсальными типами (я обнаружил, что, например, [ недопустимо, что имеет смысл, если вы об этом думаете).

Если я удаляю любые не буквенные или цифровые символы из сгенерированного имени типа, все работает как шарм.

Спасибо за ответы / комментарии!

1 голос
/ 08 ноября 2011

Вам необходимо определить (виртуальные абстрактные) методы для интерфейсов, поскольку вы создаете абстрактный класс, а не интерфейс. Несколько ошибок:

  1. Когда вы перечисляете методы интерфейса, он не будет включать методы из унаследованных интерфейсов. Вам нужно пройти через унаследованные интерфейсы, а также интерфейсы, которые они наследуют и т. Д., Рекурсивно, чтобы найти все методы, которые вам нужно определить.

  2. При обходе интерфейсов вам потребуется обработать случай, когда два интерфейса наследуют один и тот же интерфейс, чтобы не пытаться создать метод дважды.

  3. В случае, если у вас есть два интерфейса, содержащие метод с одинаковой сигнатурой, вам нужно будет создать явные реализации. Они не могут быть абстрактными виртуальными (по крайней мере, если вы хотите следовать соглашениям C #), поэтому вам нужно будет отправить некоторый код IL для пересылки в другой виртуальный абстрактный метод.


На самом деле, я просто заметил, что вы на самом деле не указали, что это класс в атрибутах типа. Вам необходимо включить TypeAttributes.Class или TypeAttributes.Interface. В последнем случае вам не нужно выполнять всю вышеперечисленную работу (и вам не понадобится аннотация, если я правильно помню).

...