Créer un délégué à partir du constructeur

.net-4.5 c# expression-trees reflection

Question

En utilisant la réflexion, j'essaie de créer un délégué à partir d'un constructeur sans paramètre comme ceci:

Delegate del = GetMethodInfo( () => System.Activator.CreateInstance( type ) ).CreateDelegate( delType );

static MethodInfo GetMethodInfo( Expression<Func<object>> func )
{
    return ((MethodCallExpression)func.Body).Method;
}

Mais j'obtiens cette exception: "Impossible de se connecter à la méthode cible car sa signature ou sa transparence de sécurité n'est pas compatible avec celle du type délégué." Qu'est-ce qui va marcher?

Notez que CreateDelegate a été déplacé, du moins pour ce profil, depuis la version précédente de .NET. Maintenant c'est sur MethodInfo.

Réponse acceptée

Comme le fait remarquer phoog, un constructeur ne "retourne" pas une valeur; De plus, vous obtenez des informations à ce sujet avec ConstructorInfo et non avec MethodInfo ; ce qui signifie que vous ne pouvez pas créer de délégué directement. Vous devez créer un code qui appelle le constructeur et renvoie la valeur. Par exemple:

var ctor = type.GetConstructor(Type.EmptyTypes);
if (ctor == null) throw new MissingMethodException("There is no constructor without defined parameters for this object");
DynamicMethod dynamic = new DynamicMethod(string.Empty,
            type,
            Type.EmptyTypes,
            type);
ILGenerator il = dynamic.GetILGenerator();

il.DeclareLocal(type);
il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ret);

var func = (Func<object>)dynamic.CreateDelegate(typeof(Func<object>));

Bien sûr, si vous ne connaissez pas le type au moment de la compilation, vous ne pouvez traiter qu'avec Object ...


Réponse populaire

Il ne serait pas très utile d’avoir un délégué pointant vers un constructeur, car les constructeurs n’ont pas de valeur de retour. Le délégué construirait un objet mais ne vous donnerait aucun moyen de conserver une référence.

Vous pouvez bien sûr créer des délégués qui renvoient l’objet nouvellement construit:

Func<object> theDelegate = () => new object();

Vous pouvez également créer un délégué à partir de la méthode Invoke() de ConstructorInfo du ConstructorInfo

Pour les autres types d'objets:

Func<string> theDelegate = () => new string('w', 3);
Func<SomeClassInMyProject> theDelegate = () => new SomeClassInMyProject();

La dernière ligne suppose qu'il existe un constructeur accessible sans paramètre.

Mise à jour avec CreateDelegate()

T CallConstructor<T>() where T : new() { return new T(); }
Delegate MakeTheDelegate(Type t)
{
    MethodInfo generic = //use your favorite technique to get the MethodInfo for the CallConstructor method
    MethodInfo constructed = generic.MakeGenericMethod(t);
    Type delType = typeof(Func<>).MakeGenericType(t);
    return constructed.CreateDelegate(delType);
}



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi