Pregunta

Tengo un tipo que se crea en tiempo de ejecución (a través de la compilación de Codedom) e implementa una interfaz conocida (en tiempo de compilación).

Supongamos que la interfaz es IMyInterface, y tengo la instancia de tipo Type myType que adquirí del ensamblaje que acabo de compilar de la codedom. La clase que myType representa implementos IMyInterface.

Me gustaría conseguir un delegado Func<IMyInterface> que, cuando se invoque, devolverá una instancia de myType.

Algo que me gustaría llamar de esta manera:

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

Sé que si tengo un MethodInfo m Para un método sin parámetros que devuelve una instancia de objeto myType, entonces podría hacer algo como esto:

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

Pero si no tengo ese método, y lo único que tengo es el constructor sin parámetros del tipo, ¿cómo obtengo este delegado?

Actualizar

Aunque la respuesta de Fsimonazzi hizo exactamente lo que estaba pidiendo, mi enfoque era un poco diferente.

Ya que controlo la creación y la compilación del myType Tipo, agregué un método estático público que devuelve una instancia de ese tipo. Luego, después de compilar este tipo, obtuve una instancia de MethodInfo para este método y creé el delegado deseado llamando delegado.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);

El código anterior genera este código y pone en la declaración de clase

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

Ahora compilando este código y tener un myType Escriba instancia para esta clase, puedo hacer

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

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

Solución

Puede compilar una expresión de lambda simple para obtener su delegado.

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

Otros consejos

Puedes usar Activator.CreateInstance( type ) para crear realmente una instancia de su tipo. Si quieres esto relleno en un Func<IMyInterface> Entonces puedes envolverlo en una lambda:

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

ACTUALIZAR:

Ya que Activator.CreateInstance Evidentemente, no es lo que está buscando (aunque no estoy completamente seguro de por qué), supongo que podría usar la reflexión para encontrar el constructor sin parámetros del 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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top