Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Saat Anda menggunakan pantulan untuk memuat dan menjalankan rakitan, Anda tidak dapat menggunakan fitur bahasa seperti operator C# += atau pernyataan Visual Basic AddHandler untuk menghubungkan peristiwa. Prosedur berikut menunjukkan cara menghubungkan metode yang ada ke suatu peristiwa dengan mendapatkan semua jenis yang diperlukan melalui pantulan, dan cara membuat metode dinamis menggunakan pancaran pantulan dan menghubungkannya ke suatu peristiwa.
Nota
Untuk cara lain untuk menghubungkan delegasi penanganan peristiwa, lihat contoh kode untuk AddEventHandler metode EventInfo kelas.
Untuk menghubungkan delegasi menggunakan pantulan
Muat assembly yang berisi tipe yang memunculkan peristiwa. Rakitan biasanya dimuat menggunakan metode Assembly.Load. Untuk menjaga contoh ini tetap sederhana, bentuk turunan dalam rakitan saat ini digunakan, sehingga metode GetExecutingAssembly digunakan untuk memuat rakitan saat ini.
Assembly assem = typeof(Example).Assembly;Dim assem As Assembly = GetType(Example).AssemblyDapatkan objek yang mewakili jenis tersebut, dan buat contoh dari jenis tersebut. Metode CreateInstance(Type) ini digunakan dalam kode berikut karena formulir memiliki konstruktor tanpa parameter. Ada beberapa overload dari metode CreateInstance yang dapat Anda gunakan jika tipe yang Anda buat tidak memiliki konstruktor tanpa parameter. Instans baru disimpan sebagai jenis Object untuk mempertahankan ilusi bahwa tidak ada yang diketahui tentang kode rakitan. (Refleksi memungkinkan Anda untuk mendapatkan tipe dalam sebuah assembly tanpa mengetahui namanya terlebih dahulu.)
Type tExForm = assem.GetType("ExampleForm"); Object exFormAsObj = Activator.CreateInstance(tExForm);Dim tExForm As Type = assem.GetType("ExampleForm") Dim exFormAsObj As Object = _ Activator.CreateInstance(tExForm)Dapatkan objek EventInfo yang mewakili peristiwa, dan gunakan properti EventHandlerType untuk mendapatkan jenis delegasi yang digunakan untuk menangani peristiwa. Dalam kode berikut, didapatkan EventInfo untuk peristiwa Click.
EventInfo evClick = tExForm.GetEvent("Click"); Type tDelegate = evClick.EventHandlerType;Dim evClick As EventInfo = tExForm.GetEvent("Click") Dim tDelegate As Type = evClick.EventHandlerTypeDapatkan objek MethodInfo yang mewakili metode yang menangani event. Kode program lengkap di bagian Contoh nanti dalam artikel ini berisi metode yang cocok dengan tanda tangan EventHandler delegasi, yang menangani Click peristiwa, tetapi Anda juga dapat menghasilkan metode dinamis saat runtime. Untuk detailnya, lihat prosedur yang menyertainya, untuk menghasilkan penanganan aktivitas saat runtime dengan menggunakan metode dinamis.
MethodInfo miHandler = typeof(Example).GetMethod("LuckyHandler", BindingFlags.NonPublic | BindingFlags.Instance);Dim miHandler As MethodInfo = _ GetType(Example).GetMethod("LuckyHandler", _ BindingFlags.NonPublic Or BindingFlags.Instance)Buat instans delegasi, menggunakan metode CreateDelegate. Metode ini statis (
Shareddalam Visual Basic), sehingga jenis delegasi harus disediakan. Disarankan menggunakan overload CreateDelegate yang menggunakan MethodInfo.Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);Dim d As [Delegate] = _ [Delegate].CreateDelegate(tDelegate, Me, miHandler)addDapatkan metode aksesor dan panggil untuk menghubungkan peristiwa. Semua event memilikiaddaksesor danremoveaksesor, disembunyikan oleh sintaks bahasa tingkat tinggi. Misalnya, C# menggunakan+=operator untuk menghubungkan peristiwa, dan Visual Basic menggunakan pernyataan AddHandler. Kode berikut mendapatkan aksesoradddari peristiwa Click dan memanggilnya secara late-bound, dengan meneruskan instance delegasi. Argumen harus diteruskan sebagai array.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)Uji acara. Kode berikut menunjukkan formulir yang ditentukan dalam contoh kode. Mengklik formulir memanggil penanganan aktivitas.
Application.Run((Form) exFormAsObj);Application.Run(CType(exFormAsObj, Form))
Membuat penanganan aktivitas saat runtime dengan menggunakan metode dinamis
Metode penanganan aktivitas dapat dihasilkan pada runtime, menggunakan metode dinamis ringan dan pancaran pantulan. Untuk membuat penanganan aktivitas, Anda memerlukan jenis pengembalian dan jenis parameter delegasi. Ini dapat diperoleh dengan memeriksa metode milik delegasi
Invoke. Kode berikut menggunakanGetDelegateReturnTypemetode danGetDelegateParameterTypesuntuk mendapatkan informasi ini. Kode untuk metode ini dapat ditemukan di bagian Contoh nanti di artikel ini.Tidak perlu memberi DynamicMethodnama , sehingga string kosong dapat digunakan. Dalam kode berikut, argumen terakhir mengaitkan metode dinamis dengan tipe saat ini, memberikan delegasi akses ke semua anggota dari kelas
Exampleyang bersifat publik dan privat.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) _ )Hasilkan isi metode. Metode ini memuat string, memanggil overload dari metode MessageBox.Show yang mengambil string, menghapus nilai pengembalian dari tumpukan (karena handler tidak memiliki jenis pengembalian), dan kemudian kembali. Untuk mempelajari selengkapnya tentang memancarkan metode dinamis, lihat Cara: Menentukan dan Menjalankan Metode Dinamis.
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)Selesaikan metode dinamis dengan memanggil metodenya CreateDelegate . Gunakan aksesor
adduntuk menambahkan delegasi ke daftar pemanggilan untuk peristiwa tersebut.Delegate dEmitted = handler.CreateDelegate(tDelegate); addHandler.Invoke(exFormAsObj, new Object[] { dEmitted });Dim dEmitted As [Delegate] = handler.CreateDelegate(tDelegate) miAddHandler.Invoke(exFormAsObj, New Object() {dEmitted})Uji acara. Kode berikut memuat formulir yang ditentukan dalam contoh kode. Mengklik formulir memanggil penanganan aktivitas yang telah ditentukan sebelumnya dan penanganan aktivitas yang dipancarkan.
Application.Run((Form) exFormAsObj);Application.Run(CType(exFormAsObj, Form))
Contoh
Contoh kode berikut menunjukkan cara menghubungkan metode yang ada ke peristiwa menggunakan pantulan, dan juga cara menggunakan DynamicMethod kelas untuk memancarkan metode saat runtime dan menghubungkannya ke peristiwa.
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