Pergunta

Eu tenho um tipo criado em tempo de execução (por meio da compilação da CodEdom) e implementa uma interface conhecida (no momento da compilação).

Suponha que a interface seja IMyInterface, e eu tenho a instância do tipo Type myType que adquiri da Assembléia, acabei de compilar a partir do codificador. A classe que myType representa implementos IMyInterface.

Eu gostaria de obter um delegado Func<IMyInterface> que, quando invocado, retornará uma instância de myType.

Algo que eu gostaria de ligar dessa maneira:

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

Eu sei que se eu tiver um MethodInfo m Para um método sem parâmetros que retorna uma instância do objeto MyType, então eu poderia fazer algo assim:

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

Mas se eu não tenho esse método, e a única coisa que tenho é o construtor sem parâmetros do tipo, como faço para obter esse delegado?

Atualizar

Embora a resposta de Fsimonazzi tenha feito exatamente o que eu estava pedindo, minha abordagem foi um pouco diferente.

Desde que eu controlo a criação e compilação do myType Tipo, adicionei um método estático público que retorna uma instância desse tipo. Então, depois de compilar esse tipo, obtive uma instância do Methodinfo para esse método e criei o delegado desejado delegate.createlegate.

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);

O código acima gera este código e coloca na declaração de classe

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

Agora compilando este código e tendo um myType Digite a instância para esta classe, eu posso fazer

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

IMyInterface obj = createObject(); // This will call MyClass.__Instantiator()
Foi útil?

Solução

Você pode compilar uma expressão simples de lambda para obter seu delegado.

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

Outras dicas

Você pode usar Activator.CreateInstance( type ) para realmente criar uma instância do seu tipo. Se você quer isso recheado em um Func<IMyInterface> Então você pode simplesmente embrulhá -lo em um lambda:

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

ATUALIZAR:

Desde Activator.CreateInstance Evidentemente, não é o que você está procurando (embora eu não tenha muita certeza do porquê), suponho que você possa usar a reflexão para encontrar o construtor sem parâmetros do tipo:

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 );
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top