Question

J'ai un type qui est créé au moment de l'exécution (via la compilation à partir de la codéme) et implémente une interface connue (au moment de la compilation).

Supposons que l'interface soit IMyInterface, et j'ai l'instance de type Type myType que j'ai acquis de l'assemblage que je viens de compiller à partir de la codéme. La classe qui myType représente les outils IMyInterface.

Je voudrais obtenir un délégué Func<IMyInterface> que, une fois invoqué, renverra une instance de myType.

Quelque chose que je voudrais appeler de cette manière:

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

Je sais que si j'ai un MethodInfo m Pour une méthode sans paramètre qui renvoie une instance d'objet myType, alors je pourrais faire quelque chose comme ceci:

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

Mais si je n'ai pas une telle méthode, et la seule chose que j'ai est le constructeur sans paramètre du type, alors comment obtenir ce délégué?

Mise à jour

Bien que la réponse de Fsimonazzi ait fait exactement ce que je demandais, mon approche était un peu différente.

Puisque je contrôle la création et la compilation du myType Type, j'ai ajouté une méthode statique publique qui renvoie une instance de ce type. Ensuite, après avoir compilé ce type, j'ai obtenu une instance MethodInfo pour cette méthode et j'ai créé le délégué délégué souhaité Delegate.CreateElegate.

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

Le code ci-dessus génère ce code et met dans la déclaration de classe

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

Maintenant compiler ce code et avoir un myType Tapez l'instance pour cette classe, je peux faire

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

IMyInterface obj = createObject(); // This will call MyClass.__Instantiator()
Était-ce utile?

La solution

Vous pouvez compiler une expression Lambda simple pour obtenir votre délégué.

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

Autres conseils

Vous pouvez utiliser Activator.CreateInstance( type ) Pour créer réellement une instance de votre type. Si vous voulez que ce soit bourré dans un Func<IMyInterface> Ensuite, vous pouvez simplement l'envelopper dans une lambda:

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

METTRE À JOUR:

Depuis Activator.CreateInstance n'est évidemment pas ce que vous recherchez (même si je ne sais pas tout à fait pourquoi), je suppose que vous pouvez utiliser la réflexion pour trouver le constructeur sans paramètre du type:

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 );
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top