Crea delegato dal costruttore

.net-4.5 c# expression-trees reflection

Domanda

Usando il reflection, sto provando a creare un delegato da un costruttore senza parametri come questo:

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

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

Ma ottengo questa eccezione: "Impossibile associare al metodo di destinazione perché la sua firma o trasparenza di sicurezza non è compatibile con quella del tipo di delegato." Cosa funzionerà?

Si noti che CreateDelegate è stato spostato, almeno per questo profilo, dalla versione precedente di .NET. Ora è su MethodInfo.

Risposta accettata

Come fa notare phoog, un costruttore non "restituisce" un valore; in più ottieni informazioni su di esso con ConstructorInfo e non con MethodInfo ; il che significa che non è possibile creare direttamente un delegato attorno ad esso. Devi creare un codice che invochi il costruttore e restituisce il valore. Per esempio:

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

Naturalmente, se non si conosce il tipo in fase di compilazione, è possibile gestire solo Object ...


Risposta popolare

Non sarebbe molto utile avere un delegato che punti a un costruttore, poiché i costruttori non hanno un valore di ritorno. Il delegato costruisce un oggetto ma non ti dà modo di mantenere un riferimento ad esso.

Ovviamente puoi creare delegati che restituiscono l'oggetto di nuova costruzione:

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

È anche possibile creare un delegato dal metodo Invoke() del ConstructorInfo del ConstructorInfo

Per altri tipi di oggetti:

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

L'ultima riga presuppone che ci sia un costruttore parametrico accessibile.

Aggiorna con 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);
}


Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché