Создайте делегат из конструктора неизвестного типа, реализуя известный интерфейс

StackOverflow https://stackoverflow.com/questions/20353277

Вопрос

У меня есть тип, который создается во время выполнения (посредством компиляции из Codedom) и реализует известный (при компиляции) интерфейс.

Предположим, что интерфейс IMyInterface, и у меня есть экземпляр типа Type myType Что я приобрел из сборки, которую я только что собрал из кодирования. Класс, что myType представляет орудия IMyInterface.

Я хотел бы получить делегата Func<IMyInterface> что, когда вы приведут myType.

Что -то, что я хотел бы позвонить таким образом:

Func<IMyInterface> createObject = GetObjectCreator<IMyInterface>(myType);
IMyInterface myObject = createObject();

Я знаю, что если у меня есть MethodInfo m Для метода без параметра, который возвращает экземпляр объекта Mytype, тогда я мог бы сделать что -то подобное:

Func<IMyInterface> createObject =
  ( Func<IMyInterface> )Delegate.CreateDelegate(typeof(Func<IMyInterface>), m);

Но если у меня нет такого метода, и единственное, что у меня есть, это конструктор без параметра, то как мне получить этот делегат?

Обновлять

Хотя ответ Fsimonazzi сделал именно то, о чем я просил, мой подход был немного другим.

Поскольку я контролирую создание и сборник myType Тип, я добавил общественный статический метод, который возвращает экземпляр такого типа. Затем, после составления этого типа, я получил экземпляр MethodInfo для этого метода и создал желаемый делегат Callgate.createdelegate.

CodeTypeDeclaration type = new CodeTypeDeclaration
{
    Name = "MyClass",
    IsClass = true,
    TypeAttributes = TypeAttributes.Public
};

type.BaseTypes.Add(new CodeTypeReference(typeof(IMyInterface)));

// fullName is the full name of the myType (including namespace)
var staticInstantiator = new CodeMemberMethod
{
    Name = "__Instantiator",
    ReturnType = new CodeTypeReference("MyNamespace.MyClass"),
    Attributes = MemberAttributes.Public | MemberAttributes.Static
};

staticInstantiator.Statements.Add(
   new CodeMethodReturnStatement(
       new CodeObjectCreateExpression("MyNamespace.MyClass")));

    type.Members.Add(staticInstantiator);

Приведенный выше код генерирует этот код и входит в объявление класса

public static MyNamespace.MyClass __Instantiator()
{
    return new MyNamespace.MyClass();
}

Теперь собирать этот код и иметь myType Тип экземпляра для этого класса, я могу сделать

Func<IMyInterface> createObject = ( Func<IMyInterface> )(
    Delegate.CreateDelegate(typeof(Func<IMyInterface>),
                            myType.GetMethod("__Instantiator")) );

IMyInterface obj = createObject(); // This will call MyClass.__Instantiator()
Это было полезно?

Решение

Вы можете собрать простое выражение Lambda, чтобы получить свой делегат.

var del = Expression.Lambda<Func<IMyInterface>>(Expression.New(type)).Compile();

Другие советы

Вы можете использовать Activator.CreateInstance( type ) Чтобы фактически создать экземпляр вашего типа. Если вы хотите набиться в Func<IMyInterface> Тогда вы можете просто обернуть его в лямбду:

Func<IMyInterface> createObject = () => (IMyInterface) Activator.CreateInstance( myType );
IMyInterface myObject = createObject();

ОБНОВИТЬ:

С Activator.CreateInstance Очевидно, не то, что вы ищете (хотя я не совсем уверен, почему), я полагаю, вы могли бы использовать отражение, чтобы найти конструктор без параметра типа:

public Func<T> GetObjectCreator<T>( Type type )
{
    // I'd probably add additional checks here to see that the
    // conversion to T is actually possible.

    var ctor = type.GetConstructor( Type.EmptyTypes );

    if( ctor == null ) throw new ArgumentException( "type", "Public parameterless constructor not found." )

    return () => (T) ctor.Invoke( null );
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top