مشاركة عبر


كيفية القيام بما يلي: الربط لأعلى تفويض استخدام الانعكاس

When you استخدم انعكاس إلى تحميل و تشغيل تجميعات, you cannot استخدم اللغة features مثل the C# += عامل أو the Visual أساسى AddHandler كشف إلى hook لأعلى أحداث. The following إجراءات إظهار how إلى hook لأعلى an موجود أسلوب إلى an حدث بواسطة getting الجميع the necessary أنواع through انعكاس, و how إلى إنشاء a ديناميكي أسلوب using انعكاس emit و hook it لأعلى إلى an حدث.

ملاحظةملاحظة

For another way إلى hook لأعلى an حدث-handling تفويض, see the تعليمات برمجية مثال for the AddEventHandler أسلوب of the EventInfo فئة.

إلى hook لأعلى a تفويض using انعكاس

  1. تحميل an تجميع that يحتوي على a نوع that raises أحداث. تجميعات are usually تم تحميله مع the Assembly.Load أسلوب. إلى احتفظ this مثال simple, a derived نموذج في the الحالي تجميع هو used, so the GetExecutingAssembly أسلوب هو used إلى تحميل the الحالي تجميع.

    Dim assem As [Assembly] = [Assembly].GetExecutingAssembly()
    
    Assembly assem = Assembly.GetExecutingAssembly();
    
  2. يحصل a Type كائن representing the نوع, و إنشاء an مثيل of the نوع. The CreateInstance(Type) أسلوب هو used في the following تعليمات برمجية because the نموذج has a الافتراضي الدالة الإنشائية. There are several غير ذلك التحميلات الزائدة of the CreateInstance أسلوب that you can استخدم if the نوع you are creating does not have a الافتراضي الدالة الإنشائية. The جديد مثيل هو stored كـ نوع Object إلى maintain the fiction that لا شيء هو known حول the تجميع. (انعكاس allows you إلى يحصل the أنواع في an تجميع without knowing their أسماء في advance.)

    Dim tExForm As Type = assem.GetType("ExampleForm")
    Dim exFormAsObj As Object = _
        Activator.CreateInstance(tExForm)
    
    Type tExForm = assem.GetType("ExampleForm");
    Object exFormAsObj = Activator.CreateInstance(tExForm);
    
  3. يحصل an EventInfo كائن representing the حدث, و استخدم the EventHandlerType خاصية إلى يحصل the نوع of تفويض used إلى مؤشر the حدث. في التعليمة البرمجية التالية، EventInfo Clickحدث هو الحصول عليه.

    Dim evClick As EventInfo = tExForm.GetEvent("Click")
    Dim tDelegate As Type = evClick.EventHandlerType
    
    EventInfo evClick = tExForm.GetEvent("Click");
    Type tDelegate = evClick.EventHandlerType;
    
  4. يحصل MethodInfoيمثل الكائن أسلوب الذي يتعامل مع حدث. البرنامج كامل تعليمات برمجية في المثال يحتوي مقطع لاحقاً في هذا الموضوع على أسلوب الذي يتطابق مع توقيع من EventHandlerتفويض أي مؤشرات Clickحدث، ولكن يمكن توليد أساليب ديناميكية في وقت التشغيل. للحصول على التفاصيل، انظر المرافق إجراء إلى إنشاء معالج أحداث في "وقت التشغيل" باستخدام "أسلوب الديناميكية" .

    Dim miHandler As MethodInfo = _
        GetType(Example).GetMethod("LuckyHandler", _
            BindingFlags.NonPublic Or BindingFlags.Instance)
    
    MethodInfo miHandler = 
        typeof(Example).GetMethod("LuckyHandler", 
            BindingFlags.NonPublic | BindingFlags.Instance);
    
  5. إنشاء مثيل تفويض، استخدام CreateDelegateالأسلوب. Th هو أسلوب هو ثابتة ( Sharedفي Vهوual الأساسية)، لذلك يجب توفير نوع المفوض. استخدام التحميلات الزائدة من CreateDelegateأن تأخذ MethodInfoهو مستحسن.

    Dim d As [Delegate] = _
        [Delegate].CreateDelegate(tDelegate, Me, miHandler)
    
    Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);
    
  6. يحصل addالأسلوب أسلوب استرجاع قيمة واستدعاء فإنه إلى ربط حدث. تحتوي الجميع الأحداث addأسلوب استرجاع قيمة و removeواصف الوصول التي تم إخفاؤها وفق بناء جملة لغة عالية المستوى. على سبيل المثال، C# يستخدم +=operaإلىr إلى ربط الأحداث، ويستخدم Visual أساسى كشف AddHandler. إحضار تعليمات برمجية التالية addأسلوب استرجاع قيمة من Clickحدث وقم باستدعاء المتأخر منضم، تمرير في تفويض المثيل. يجب أن يتم تمرير الوسيطات كصفيف.

    Dim miAddHandler As MethodInfo = evClick.GetAddMethod()
    Dim addHandlerArgs() As Object = { d }
    miAddHandler.Invoke(exFormAsObj, addHandlerArgs)
    
    MethodInfo addHandler = evClick.GetAddMethod();
    Object[] addHandlerArgs = { d };
    addHandler.Invoke(exFormAsObj, addHandlerArgs);
    
  7. قم باختبار حدث. يلي تعليمات برمجية يعرض النموذج المعرفة في تعليمات برمجية المثال. استدعاء بالنقر فوق النموذج حدث معالج.

    Application.Run(CType(exFormAsObj, Form))
    
    Application.Run((Form) exFormAsObj);
    

إلى إنشاء معالج أحداث في وقت التشغيل باستخدام أسلوب ديناميكية

  1. وظائف حدث-hوler يمكن إنشاؤها أثناء وقت التشغيل، استخدام الوظائف الديناميكية الخفيف و انعكاس الإرسال. إلى إنشاء معالج أحداث، تحتاج نوع الإرجاع وأنواع المعلمات للمفوض. الحصول على هذه بواسطة فحص تفويض's Invokeالأسلوب. يلي تعليمات برمجية يستخدم في GetDelegateReturnType GetDelegateParameterTypesوظائف للحصول على هذه المعلومات. تعليمات برمجية لهذه الطرق التي يمكن العثور في مقطع مثال لاحقاً في هذا الموضوع.

    هو غير ضرورية لتسمية DynamicMethod، لذلك يمكن استخدام السلسلة الفارغة. في ما يلي تعليمات برمجية، يربط وسيطة الأخيرة الأسلوب الحيوي مع النوع الحالي، بمنح المفوض الوصول إلى الجميع المستخدمين وخاصة الأعضاء Exampleفئة.

    Dim returnType As Type = GetDelegateReturnType(tDelegate)
    If returnType IsNot GetType(Void) Then
        Throw New ApplicationException("Delegate has a return type.")
    End If
    
    Dim handler As New DynamicMethod( _
        "", _
        Nothing, _
        GetDelegateParameterTypes(tDelegate), _
        GetType(Example) _
    )
    
    Type returnType = GetDelegateReturnType(tDelegate);
    if (returnType != typeof(void))
        throw new ApplicationException("Delegate has a return type.");
    
    DynamicMethod handler = 
        new DynamicMethod("", 
                          null,
                          GetDelegateParameterTypes(tDelegate),
                          typeof(Example));
    
  2. توليد نص أسلوب. قم بتحميل سلسلة هذه الطريقة، قم باستدعاء التحميل الزائد من MessageBox.Showالطريقة التي تأخذ سلسلة، ويخرج القيمة المرجعة إيقاف المكدس (لأن hوler لا يوجد نوع الإرجاع)، و. إرجاع لمعرفة المزيد حول باعث ديناميكي الأساليب، راجع كيفية القيام بما يلي: تعريف و تنفيذ وظائف ديناميكية.

    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)
    
    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);
    
  3. إكمال أسلوب حيوي بواسطة استدعاء له CreateDelegateالأسلوب. استخدام addأسلوب استرجاع قيمة لإضافة المفوض إلى قائمة الاستدعاء حدث.

    Dim dEmitted As [Delegate] = handler.CreateDelegate(tDelegate)
    miAddHandler.Invoke(exFormAsObj, New Object() { dEmitted })
    
    Delegate dEmitted = handler.CreateDelegate(tDelegate);
    addHandler.Invoke(exFormAsObj, new Object[] { dEmitted });
    
  4. قم باختبار حدث. التحميلات التعليمة البرمجية التالية نموذج المعرفة في مثال التعليمة البرمجية. النقر فوق النموذج إلى استدعاء معالج الأحداث emitted ومعالج الأحداث المعرفة مسبقاً.

    Application.Run(CType(exFormAsObj, Form))
    
    Application.Run((Form) exFormAsObj);
    

مثال

The following تعليمات برمجية مثال shows how إلى hook لأعلى an موجود أسلوب إلى an حدث using انعكاس, و also how إلى استخدم the DynamicMethod فئة إلى emit a أسلوب at تشغيل الوقت و hook it لأعلى إلى an حدث.

Imports System
Imports System.Reflection
Imports System.Reflection.Emit
Imports System.Windows.Forms

Class ExampleForm
    Inherits Form

    Public Sub New() 
        Me.Text = "Click me"

    End Sub 'New
End Class 'ExampleForm

Class Example

    Public Shared Sub Main() 
        Dim ex As New Example()
        ex.HookUpDelegate()
    End Sub 'Main

    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] = [Assembly].GetExecutingAssembly()

        ' 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 ApplicationException("Delegate has a return type.")
        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 ApplicationException("Not a delegate.")
        End If

        Dim invoke As MethodInfo = d.GetMethod("Invoke")
        If invoke Is Nothing Then
            Throw New ApplicationException("Not a delegate.")
        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 ApplicationException("Not a delegate.")
        End If

        Dim invoke As MethodInfo = d.GetMethod("Invoke")
        If invoke Is Nothing Then
            Throw New ApplicationException("Not a delegate.")
        End If

        Return invoke.ReturnType

    End Function 
End Class 
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 = Assembly.GetExecutingAssembly();

        // 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 ApplicationException("Delegate has a return type.");

        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 ApplicationException("Not a delegate.");

        MethodInfo invoke = d.GetMethod("Invoke");
        if (invoke == null)
            throw new ApplicationException("Not a delegate.");

        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 ApplicationException("Not a delegate.");

        MethodInfo invoke = d.GetMethod("Invoke");
        if (invoke == null)
            throw new ApplicationException("Not a delegate.");

        return invoke.ReturnType;
    }
}

التحويل البرمجي للتعليمات البرمجية

  • The تعليمات برمجية يحتوي على the C# using statements (Imports في Visual أساسى) necessary for compilation.

  • لا توجد مراجع التجميع إضافية مطلوبة من أجل ترجمة من سطر الأوامر. في ‏‫Visual Studio you must إضافة a مرجع إلى النظام.Windows.Forms.dll because this مثال هو a تطبيق وحدة تحكم.

  • يحول برمجياً the تعليمات برمجية at the الأمر خط using csc.exe, vbc.exe, أو cl.exe. إلى يحول برمجياً the تعليمات برمجية في ‏‫Visual Studio, place it في a تطبيق وحدة تحكم قالب مشروع.

راجع أيضًا:

المهام

كيفية القيام بما يلي: تعريف و تنفيذ وظائف ديناميكية

المرجع

Assembly.Load

DynamicMethod

CreateInstance

CreateDelegate

المبادئ

انعكاس