Domanda

Ho un tipo che viene creato in fase di esecuzione (attraverso la compilation da codedom) e implementa un'interfaccia nota (al momento della compilazione).

Supponiamo che l'interfaccia sia IMyInterface, e ho l'istanza di tipo Type myType che ho acquisito dall'assemblaggio che ho appena compilato dal codedom. La classe che myType Rappresenta gli strumenti IMyInterface.

Vorrei ottenere un delegato Func<IMyInterface> che, quando invocato, restituirà un'istanza di myType.

Qualcosa che vorrei chiamare in questo modo:

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

Lo so se ho un MethodInfo m Per un metodo senza parametri che restituisce un'istanza di MyType Object, potrei fare qualcosa del genere:

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

Ma se non ho un tale metodo, e l'unica cosa che ho è il costruttore senza parametri del tipo, allora come posso ottenere questo delegato?

Aggiornare

Sebbene la risposta di Fsimonazzi abbia fatto esattamente quello che stavo chiedendo, il mio approccio era un po 'diverso.

Da quando controllo la creazione e la compilazione del myType Digita, ho aggiunto un metodo statico pubblico che restituisce un'istanza di quel tipo. Quindi, dopo aver compilato questo tipo, ho ottenuto un'istanza MethodInfo per questo metodo e ho creato il delegato delegato desiderato delegate.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);

Il codice sopra genera questo codice e inserisce nella dichiarazione di classe

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

Ora compila questo codice e avere un myType Digita l'istanza per questa classe, posso farlo

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

IMyInterface obj = createObject(); // This will call MyClass.__Instantiator()
È stato utile?

Soluzione

Puoi compilare una semplice espressione Lambda per ottenere il tuo delegato.

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

Altri suggerimenti

Puoi usare Activator.CreateInstance( type ) Per creare effettivamente un'istanza del tuo tipo. Se lo vuoi imbottito in un Func<IMyInterface> Quindi puoi semplicemente avvolgerlo in un lambda:

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

AGGIORNARE:

Da Activator.CreateInstance Evidentemente non è quello che stai cercando (anche se non sono del tutto sicuro del perché), suppongo che potresti usare la riflessione per trovare il costruttore senza parametri 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 );
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top