Verwenden von Reflection zum Aufrufen einer überladenen Methode in .NET

75

Gibt es eine Möglichkeit, eine überladene Methode mithilfe von Reflection in .NET (2.0) aufzurufen? Ich habe eine Anwendung, die Klassen, die von einer gemeinsamen Basisklasse abgeleitet wurden, dynamisch instanziiert. Aus Kompatibilitätsgründen enthält diese Basisklasse zwei gleichnamige Methoden, eine mit und eine ohne Parameter. Ich muss die parameterlose Methode über die Invoke-Methode aufrufen. Im Moment erhalte ich nur einen Fehler, der mir mitteilt, dass ich versuche, eine mehrdeutige Methode aufzurufen.

Ja, ich könnte das Objekt einfach als Instanz meiner Basisklasse umwandeln und die von mir benötigte Methode aufrufen. Irgendwann wird das passieren, aber im Moment werden interne Komplikationen es nicht zulassen.

Jede Hilfe wäre toll! Vielen Dank.

Wes P.
quelle

Antworten:

120

Sie müssen angeben, welche Methode Sie möchten:

class SomeType 
{
    void Foo(int size, string bar) { }
    void Foo() { }
}

SomeType obj = new SomeType();
// call with int and string arguments
obj.GetType()
    .GetMethod("Foo", new Type[] { typeof(int), typeof(string) })
    .Invoke(obj, new object[] { 42, "Hello" });
// call without arguments
obj.GetType()
    .GetMethod("Foo", new Type[0])
    .Invoke(obj, new object[0]);
Hallgrim
quelle
7
Sie können auch Type.EmptyTypes
yoel halb
2
brauche} nach "typeof (int), typeof (string)" zum Kompilieren :)
Omid-RH
1
Was ist, wenn eines der Argumente generisch ist?
Steven Turner
Wenn Sie eine Objektinstanz haben, wissen Sie, mit welchen Typen sie instanziiert wurde.
Hallgrim
Und wenn Sie einen out-Parameter angeben müssen, spielen Sie nicht mit Modifikatoren, das funktioniert (für mich) nicht. Sie müssen das Typobjekt übergeben, dessen IsByRef-Eigenschaft auf true festgelegt ist. IsByRef ist jedoch schreibgeschützt. Sie müssen die Typmethode MakeByRefType verwenden, um den Typ in eine Instanz zu konvertieren, für die diese Eigenschaft festgelegt ist.
Martin Maat
17

Ja. Wenn Sie die Methode aufrufen, übergeben Sie die Parameter, die der gewünschten Überladung entsprechen.

Zum Beispiel:

Type tp = myInstance.GetType();

//call parameter-free overload
tp.InvokeMember( "methodName", BindingFlags.InvokeMethod, 
   Type.DefaultBinder, myInstance, new object[0] );

//call parameter-ed overload
tp.InvokeMember( "methodName", BindingFlags.InvokeMethod, 
   Type.DefaultBinder, myInstance, new { param1, param2 } );

Wenn Sie dies umgekehrt tun (dh indem Sie MemberInfo finden und Invoke aufrufen), achten Sie darauf, dass Sie die richtige finden - die parameterfreie Überladung könnte die erste sein, die gefunden wird.

Keith
quelle
Interessanterweise hat das nicht funktioniert. Ich habe keine Parameter an meine parameterlose Methode übergeben und trotzdem einen mehrdeutigen Aufruf erhalten.
Wes P
Wie funktioniert das mit Parametern unterschiedlicher Typen? Angenommen, ich habe zwei Überladungen, bei denen eine eine Zeichenfolge und die andere eine int verwendet.
Smaclell
Kein Problem - die zugrunde liegenden Arten der Parameter werden überprüft.
Keith
Seien Sie vorsichtig, wenn Sie Typen haben, die implizit ineinander umgewandelt werden. Dann wählt .Net Instanzmethoden gegenüber geerbten Methoden aus.
Keith
In dieser Frage finden Sie ein Beispiel dafür: stackoverflow.com/questions/154112
Keith
5

Verwenden Sie die GetMethod-Überladung, die einen System.Type [] akzeptiert, und übergeben Sie einen leeren Type [].

typeof ( Class ).GetMethod ( "Method", new Type [ 0 ] { } ).Invoke ( instance, null );
Baretta
quelle
3
Sie können Type.EmptyTypes
yoel halb