Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Wenn Sie die Spiegelung zum Laden und Ausführen von Assemblys verwenden, können Sie keine Sprachfeatures wie den C# +=
-Operator oder die Visual Basic-AddHandler-Anweisung verwenden, um Ereignisse zu verbinden. Die folgenden Verfahren zeigen, wie Sie eine vorhandene Methode mit einem Ereignis verbinden, indem Sie alle erforderlichen Typen durch Spiegelung abrufen und eine dynamische Methode mithilfe von Spiegelungs-Emit erstellen und an ein Ereignis binden.
Hinweis
Eine weitere Möglichkeit zum Verbinden eines Ereignisbehandlungsdelegats finden Sie im Codebeispiel für die AddEventHandler Methode der EventInfo Klasse.
So verbinden Sie eine Stellvertretung mithilfe von Spiegelung
Laden Sie eine Assembly, die einen Typ enthält, der Ereignisse auslöst. Assemblys werden in der Regel mit der Assembly.Load Methode geladen. Um dieses Beispiel einfach zu halten, wird ein abgeleitetes Formular in der aktuellen Assembly verwendet, sodass die GetExecutingAssembly Methode zum Laden der aktuellen Assembly verwendet wird.
Assembly assem = typeof(Example).Assembly;
Dim assem As Assembly = GetType(Example).Assembly
Rufen Sie ein Type Objekt ab, das den Typ darstellt, und erstellen Sie eine Instanz des Typs. Die CreateInstance(Type) Methode wird im folgenden Code verwendet, da das Formular über einen parameterlosen Konstruktor verfügt. Es gibt mehrere andere Überladungen der CreateInstance Methode, die Sie verwenden können, wenn der typ, den Sie erstellen, keinen parameterlosen Konstruktor aufweist. Die neue Instanz wird als Typ Object gespeichert, um die Fiktion beizubehalten, dass nichts über die Assembly bekannt ist. (Reflektion ermöglicht es Ihnen, die Typen in einer Assembly abzurufen, ohne ihre Namen im Voraus zu kennen.)
Type tExForm = assem.GetType("ExampleForm"); Object exFormAsObj = Activator.CreateInstance(tExForm);
Dim tExForm As Type = assem.GetType("ExampleForm") Dim exFormAsObj As Object = _ Activator.CreateInstance(tExForm)
Rufen Sie ein EventInfo Objekt ab, das das Ereignis darstellt, und verwenden Sie die EventHandlerType Eigenschaft, um den Typ des Delegaten abzurufen, der zum Behandeln des Ereignisses verwendet wird. Im folgenden Code wird ein EventInfo Ereignis für das Click Ereignis abgerufen.
EventInfo evClick = tExForm.GetEvent("Click"); Type tDelegate = evClick.EventHandlerType;
Dim evClick As EventInfo = tExForm.GetEvent("Click") Dim tDelegate As Type = evClick.EventHandlerType
Ruft ein MethodInfo Objekt ab, das die Methode darstellt, die das Ereignis behandelt. Der vollständige Programmcode im Abschnitt "Beispiel" weiter unten in diesem Artikel enthält eine Methode, die der Signatur des EventHandler Delegaten entspricht, die das Click Ereignis behandelt, aber Sie können auch dynamische Methoden zur Laufzeit generieren. Ausführliche Informationen finden Sie in der zugehörigen Prozedur zum Generieren eines Ereignishandlers zur Laufzeit mithilfe einer dynamischen Methode.
MethodInfo miHandler = typeof(Example).GetMethod("LuckyHandler", BindingFlags.NonPublic | BindingFlags.Instance);
Dim miHandler As MethodInfo = _ GetType(Example).GetMethod("LuckyHandler", _ BindingFlags.NonPublic Or BindingFlags.Instance)
Erstellen Sie eine Instanz des Delegaten mithilfe der CreateDelegate Methode. Diese Methode ist statisch (
Shared
in Visual Basic), sodass der Delegattyp angegeben werden muss. Die Verwendung der Überladungen wird CreateDelegateMethodInfo empfohlen.Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);
Dim d As [Delegate] = _ [Delegate].CreateDelegate(tDelegate, Me, miHandler)
Rufen Sie die
add
Accessormethode ab, und rufen Sie sie auf, um das Ereignis zu verbinden. Alle Ereignisse verfügen über einenadd
Accessor und einenremove
Accessor, der durch die Syntax von Sprachen auf hoher Ebene ausgeblendet wird. Beispielsweise verwendet C# den+=
Operator, um Ereignisse zu verbinden, und Visual Basic verwendet die AddHandler-Anweisung. Der folgende Code ruft denadd
Accessor des Click Ereignisses ab und ruft es spät gebunden auf und übergibt die Delegateninstanz. Die Argumente müssen als Array übergeben werden.MethodInfo addHandler = evClick.GetAddMethod(); Object[] addHandlerArgs = { d }; addHandler.Invoke(exFormAsObj, addHandlerArgs);
Dim miAddHandler As MethodInfo = evClick.GetAddMethod() Dim addHandlerArgs() As Object = {d} miAddHandler.Invoke(exFormAsObj, addHandlerArgs)
Testen Sie das Ereignis. Der folgende Code zeigt das im Codebeispiel definierte Formular. Durch Klicken auf das Formular wird der Ereignishandler aufgerufen.
Application.Run((Form) exFormAsObj);
Application.Run(CType(exFormAsObj, Form))
Generieren eines Ereignishandlers zur Laufzeit mithilfe einer dynamischen Methode
Ereignishandlermethoden können zur Laufzeit mithilfe einfacher dynamischer Methoden und Spiegelung generiert werden. Zum Erstellen eines Ereignishandlers benötigen Sie den Rückgabetyp und die Parametertypen des Delegaten. Diese können durch Untersuchung der Methode des Stellvertreters
Invoke
abgerufen werden. Der folgende Code verwendet dieGetDelegateReturnType
undGetDelegateParameterTypes
methoden, um diese Informationen abzurufen. Der Code für diese Methoden finden Sie im Abschnitt "Beispiel" weiter unten in diesem Artikel.Es ist nicht erforderlich, einen DynamicMethodNamen zu geben, damit die leere Zeichenfolge verwendet werden kann. Im folgenden Code ordnet das letzte Argument die dynamische Methode dem aktuellen Typ zu, sodass der Delegat zugriff auf alle öffentlichen und privaten Member der
Example
Klasse erhält.Type returnType = GetDelegateReturnType(tDelegate); if (returnType != typeof(void)) throw new ArgumentException("Delegate has a return type.", nameof(d)); DynamicMethod handler = new DynamicMethod("", null, GetDelegateParameterTypes(tDelegate), typeof(Example));
Dim returnType As Type = GetDelegateReturnType(tDelegate) If returnType IsNot GetType(Void) Then Throw New ArgumentException("Delegate has a return type.", NameOf(d)) End If Dim handler As New DynamicMethod( _ "", _ Nothing, _ GetDelegateParameterTypes(tDelegate), _ GetType(Example) _ )
Generieren Sie einen Methodentext. Diese Methode lädt eine Zeichenfolge, ruft die Überladung der MessageBox.Show Methode auf, die eine Zeichenfolge akzeptiert, den Rückgabewert vom Stapel ausfüllt (da der Handler keinen Rückgabetyp hat) und gibt zurück. Weitere Informationen zum Emittieren dynamischer Methoden finden Sie unter How to: Define and Execute Dynamic Methods.
ILGenerator ilgen = handler.GetILGenerator(); Type[] showParameters = { typeof(String) }; MethodInfo simpleShow = typeof(MessageBox).GetMethod("Show", showParameters); ilgen.Emit(OpCodes.Ldstr, "This event handler was constructed at run time."); ilgen.Emit(OpCodes.Call, simpleShow); ilgen.Emit(OpCodes.Pop); ilgen.Emit(OpCodes.Ret);
Dim ilgen As ILGenerator = handler.GetILGenerator() Dim showParameters As Type() = {GetType(String)} Dim simpleShow As MethodInfo = _ GetType(MessageBox).GetMethod("Show", showParameters) ilgen.Emit(OpCodes.Ldstr, _ "This event handler was constructed at run time.") ilgen.Emit(OpCodes.Call, simpleShow) ilgen.Emit(OpCodes.Pop) ilgen.Emit(OpCodes.Ret)
Schließen Sie die dynamische Methode ab, indem Sie die CreateDelegate Methode aufrufen. Verwenden Sie den
add
Accessor, um den Delegaten zur Aufrufliste für das Ereignis hinzuzufügen.Delegate dEmitted = handler.CreateDelegate(tDelegate); addHandler.Invoke(exFormAsObj, new Object[] { dEmitted });
Dim dEmitted As [Delegate] = handler.CreateDelegate(tDelegate) miAddHandler.Invoke(exFormAsObj, New Object() {dEmitted})
Testen Sie das Ereignis. Der folgende Code lädt das im Codebeispiel definierte Formular. Durch Klicken auf das Formular werden sowohl der vordefinierte Ereignishandler als auch der ausgegebene Ereignishandler aufgerufen.
Application.Run((Form) exFormAsObj);
Application.Run(CType(exFormAsObj, Form))
Beispiel
Das folgende Codebeispiel zeigt, wie sie eine vorhandene Methode mit einem Ereignis mithilfe von Spiegelung verbinden und wie Sie die DynamicMethod Klasse verwenden, um eine Methode zur Laufzeit auszugeben und mit einem Ereignis zu verbinden.
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Windows.Forms;
class ExampleForm : Form
{
public ExampleForm() : base()
{
this.Text = "Click me";
}
}
class Example
{
public static void Main()
{
Example ex = new Example();
ex.HookUpDelegate();
}
private void HookUpDelegate()
{
// Load an assembly, for example using the Assembly.Load
// method. In this case, the executing assembly is loaded, to
// keep the demonstration simple.
//
Assembly assem = typeof(Example).Assembly;
// Get the type that is to be loaded, and create an instance
// of it. Activator.CreateInstance has other overloads, if
// the type lacks a default constructor. The new instance
// is stored as type Object, to maintain the fiction that
// nothing is known about the assembly. (Note that you can
// get the types in an assembly without knowing their names
// in advance.)
//
Type tExForm = assem.GetType("ExampleForm");
Object exFormAsObj = Activator.CreateInstance(tExForm);
// Get an EventInfo representing the Click event, and get the
// type of delegate that handles the event.
//
EventInfo evClick = tExForm.GetEvent("Click");
Type tDelegate = evClick.EventHandlerType;
// If you already have a method with the correct signature,
// you can simply get a MethodInfo for it.
//
MethodInfo miHandler =
typeof(Example).GetMethod("LuckyHandler",
BindingFlags.NonPublic | BindingFlags.Instance);
// Create an instance of the delegate. Using the overloads
// of CreateDelegate that take MethodInfo is recommended.
//
Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);
// Get the "add" accessor of the event and invoke it late-
// bound, passing in the delegate instance. This is equivalent
// to using the += operator in C#, or AddHandler in Visual
// Basic. The instance on which the "add" accessor is invoked
// is the form; the arguments must be passed as an array.
//
MethodInfo addHandler = evClick.GetAddMethod();
Object[] addHandlerArgs = { d };
addHandler.Invoke(exFormAsObj, addHandlerArgs);
// Event handler methods can also be generated at run time,
// using lightweight dynamic methods and Reflection.Emit.
// To construct an event handler, you need the return type
// and parameter types of the delegate. These can be obtained
// by examining the delegate's Invoke method.
//
// It is not necessary to name dynamic methods, so the empty
// string can be used. The last argument associates the
// dynamic method with the current type, giving the delegate
// access to all the public and private members of Example,
// as if it were an instance method.
//
Type returnType = GetDelegateReturnType(tDelegate);
if (returnType != typeof(void))
throw new ArgumentException("Delegate has a return type.", nameof(d));
DynamicMethod handler =
new DynamicMethod("",
null,
GetDelegateParameterTypes(tDelegate),
typeof(Example));
// Generate a method body. This method loads a string, calls
// the Show method overload that takes a string, pops the
// return value off the stack (because the handler has no
// return type), and returns.
//
ILGenerator ilgen = handler.GetILGenerator();
Type[] showParameters = { typeof(String) };
MethodInfo simpleShow =
typeof(MessageBox).GetMethod("Show", showParameters);
ilgen.Emit(OpCodes.Ldstr,
"This event handler was constructed at run time.");
ilgen.Emit(OpCodes.Call, simpleShow);
ilgen.Emit(OpCodes.Pop);
ilgen.Emit(OpCodes.Ret);
// Complete the dynamic method by calling its CreateDelegate
// method. Use the "add" accessor to add the delegate to
// the invocation list for the event.
//
Delegate dEmitted = handler.CreateDelegate(tDelegate);
addHandler.Invoke(exFormAsObj, new Object[] { dEmitted });
// Show the form. Clicking on the form causes the two
// delegates to be invoked.
//
Application.Run((Form) exFormAsObj);
}
private void LuckyHandler(Object sender, EventArgs e)
{
MessageBox.Show("This event handler just happened to be lying around.");
}
private Type[] GetDelegateParameterTypes(Type d)
{
if (d.BaseType != typeof(MulticastDelegate))
throw new ArgumentException("Not a delegate.", nameof(d));
MethodInfo invoke = d.GetMethod("Invoke");
if (invoke == null)
throw new ArgumentException("Not a delegate.", nameof(d));
ParameterInfo[] parameters = invoke.GetParameters();
Type[] typeParameters = new Type[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
typeParameters[i] = parameters[i].ParameterType;
}
return typeParameters;
}
private Type GetDelegateReturnType(Type d)
{
if (d.BaseType != typeof(MulticastDelegate))
throw new ArgumentException("Not a delegate.", nameof(d));
MethodInfo invoke = d.GetMethod("Invoke");
if (invoke == null)
throw new ArgumentException("Not a delegate.", nameof(d));
return invoke.ReturnType;
}
}
Imports System.Reflection
Imports System.Reflection.Emit
Imports System.Windows.Forms
Class ExampleForm
Inherits Form
Public Sub New()
Me.Text = "Click me"
End Sub
End Class
Class Example
Public Shared Sub Main()
Dim ex As New Example()
ex.HookUpDelegate()
End Sub
Private Sub HookUpDelegate()
' Load an assembly, for example using the Assembly.Load
' method. In this case, the executing assembly is loaded, to
' keep the demonstration simple.
'
Dim assem As Assembly = GetType(Example).Assembly
' Get the type that is to be loaded, and create an instance
' of it. Activator.CreateInstance also has an overload that
' takes an array of types representing the types of the
' constructor parameters, if the type you are creating does
' not have a parameterless constructor. The new instance
' is stored as type Object, to maintain the fiction that
' nothing is known about the assembly. (Note that you can
' get the types in an assembly without knowing their names
' in advance.)
'
Dim tExForm As Type = assem.GetType("ExampleForm")
Dim exFormAsObj As Object = _
Activator.CreateInstance(tExForm)
' Get an EventInfo representing the Click event, and get the
' type of delegate that handles the event.
'
Dim evClick As EventInfo = tExForm.GetEvent("Click")
Dim tDelegate As Type = evClick.EventHandlerType
' If you already have a method with the correct signature,
' you can simply get a MethodInfo for it.
'
Dim miHandler As MethodInfo = _
GetType(Example).GetMethod("LuckyHandler", _
BindingFlags.NonPublic Or BindingFlags.Instance)
' Create an instance of the delegate. Using the overloads
' of CreateDelegate that take MethodInfo is recommended.
'
Dim d As [Delegate] = _
[Delegate].CreateDelegate(tDelegate, Me, miHandler)
' Get the "add" accessor of the event and invoke it late-
' bound, passing in the delegate instance. This is equivalent
' to using the += operator in C#, or AddHandler in Visual
' Basic. The instance on which the "add" accessor is invoked
' is the form; the arguments must be passed as an array.
'
Dim miAddHandler As MethodInfo = evClick.GetAddMethod()
Dim addHandlerArgs() As Object = {d}
miAddHandler.Invoke(exFormAsObj, addHandlerArgs)
' Event handler methods can also be generated at run time,
' using lightweight dynamic methods and Reflection.Emit.
' To construct an event handler, you need the return type
' and parameter types of the delegate. These can be obtained
' by examining the delegate's Invoke method.
'
' It is not necessary to name dynamic methods, so the empty
' string can be used. The last argument associates the
' dynamic method with the current type, giving the delegate
' access to all the public and private members of Example,
' as if it were an instance method.
'
Dim returnType As Type = GetDelegateReturnType(tDelegate)
If returnType IsNot GetType(Void) Then
Throw New ArgumentException("Delegate has a return type.", NameOf(d))
End If
Dim handler As New DynamicMethod( _
"", _
Nothing, _
GetDelegateParameterTypes(tDelegate), _
GetType(Example) _
)
' Generate a method body. This method loads a string, calls
' the Show method overload that takes a string, pops the
' return value off the stack (because the handler has no
' return type), and returns.
'
Dim ilgen As ILGenerator = handler.GetILGenerator()
Dim showParameters As Type() = {GetType(String)}
Dim simpleShow As MethodInfo = _
GetType(MessageBox).GetMethod("Show", showParameters)
ilgen.Emit(OpCodes.Ldstr, _
"This event handler was constructed at run time.")
ilgen.Emit(OpCodes.Call, simpleShow)
ilgen.Emit(OpCodes.Pop)
ilgen.Emit(OpCodes.Ret)
' Complete the dynamic method by calling its CreateDelegate
' method. Use the "add" accessor to add the delegate to
' the invocation list for the event.
'
Dim dEmitted As [Delegate] = handler.CreateDelegate(tDelegate)
miAddHandler.Invoke(exFormAsObj, New Object() {dEmitted})
' Show the form. Clicking on the form causes the two
' delegates to be invoked.
'
Application.Run(CType(exFormAsObj, Form))
End Sub
Private Sub LuckyHandler(ByVal sender As [Object], _
ByVal e As EventArgs)
MessageBox.Show("This event handler just happened to be lying around.")
End Sub
Private Function GetDelegateParameterTypes(ByVal d As Type) _
As Type()
If d.BaseType IsNot GetType(MulticastDelegate) Then
Throw New ArgumentException("Not a delegate.", NameOf(d))
End If
Dim invoke As MethodInfo = d.GetMethod("Invoke")
If invoke Is Nothing Then
Throw New ArgumentException("Not a delegate.", NameOf(d))
End If
Dim parameters As ParameterInfo() = invoke.GetParameters()
' Dimension this array Length - 1, because VB adds an extra
' element to zero-based arrays.
Dim typeParameters(parameters.Length - 1) As Type
For i As Integer = 0 To parameters.Length - 1
typeParameters(i) = parameters(i).ParameterType
Next i
Return typeParameters
End Function
Private Function GetDelegateReturnType(ByVal d As Type) As Type
If d.BaseType IsNot GetType(MulticastDelegate) Then
Throw New ArgumentException("Not a delegate.", NameOf(d))
End If
Dim invoke As MethodInfo = d.GetMethod("Invoke")
If invoke Is Nothing Then
Throw New ArgumentException("Not a delegate.", NameOf(d))
End If
Return invoke.ReturnType
End Function
End Class