Puoi compilare una semplice espressione Lambda per ottenere il tuo delegato.
var del = Expression.Lambda<Func<IMyInterface>>(Expression.New(type)).Compile();
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?
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()
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 );
}