首頁 > 後端開發 > C++ > 如何使用通用 FromEvent 方法等待任何類型的任何事件?

如何使用通用 FromEvent 方法等待任何類型的任何事件?

Mary-Kate Olsen
發布: 2024-12-31 22:38:19
原創
939 人瀏覽過

How Can I Await Any Event on Any Type Using a General-Purpose FromEvent Method?

通用 FromEvent 方法

原始的 FromEvent 方法需要為每個要等待的事件和類別建立單獨的方法。為了消除樣板程式碼,開發人員尋求更通用的解決方案。

一種方法涉及使用反射來檢索事件及其委託類型。然而,存取委託的參數和修改 TaskCompletionSource 帶來了挑戰。

自訂解決方案

這是一個利用 IL 發射和事件處理程序的自訂解決方案:

public static class ExtensionMethods
{
    public static Task<object[]> FromEvent<T>(this T obj, string eventName)
    {
        // Create a TaskCompletionSourceHolder to manage the TaskCompletionSource and event handler
        var tcsh = new TaskCompletionSourceHolder();

        // Get the event and its delegate type
        EventInfo eventInfo = obj.GetType().GetEvent(eventName);
        Type eventDelegateType = eventInfo.EventHandlerType;

        // Create a dynamic method to handle the event
        DynamicMethod handler = CreateEventHandler(eventDelegateType);

        // Add the event handler to the target object
        eventInfo.AddEventHandler(obj, handler.CreateDelegate(eventDelegateType, tcsh));

        // Return the Task from the TaskCompletionSourceHolder
        return tcsh.Task;
    }

    private static DynamicMethod CreateEventHandler(Type eventDelegateType)
    {
        // Get the parameter types of the event delegate
        var parameterTypes = GetDelegateParameterTypes(eventDelegateType);

        // Insert the TaskCompletionSourceHolder as the first parameter
        parameterTypes.Insert(0, typeof(TaskCompletionSourceHolder));

        // Create a new dynamic method and IL generator
        DynamicMethod handler = new DynamicMethod("EventHandler", typeof(void), parameterTypes, true);
        ILGenerator ilgen = handler.GetILGenerator();

        // Load the TaskCompletionSourceHolder and create an array to store the arguments
        ilgen.Emit(OpCodes.Ldarg_0);
        ilgen.Emit(OpCodes.Ldc_I4, parameterTypes.Count - 1);
        ilgen.Emit(OpCodes.Newarr, typeof(object));

        // Store each argument in the array
        for (int i = 1; i < parameterTypes.Count; i++)
        {
            ilgen.Emit(OpCodes.Ldloc_0);
            ilgen.Emit(OpCodes.Ldc_I4, i - 1);
            ilgen.Emit(OpCodes.Ldarg, i);
            ilgen.Emit(OpCodes.Stelem_Ref);
        }

        // Call the SetResult method on the TaskCompletionSourceHolder
        ilgen.Emit(OpCodes.Call, typeof(TaskCompletionSourceHolder).GetMethod("SetResult"));

        // Return from the method
        ilgen.Emit(OpCodes.Ret);

        return handler;
    }

    private static List<Type> GetDelegateParameterTypes(Type delegateType)
    {
        var parameters = delegateType.GetMethod("Invoke").GetParameters();
        var parameterTypes = parameters.Select(p => p.ParameterType).ToList();
        return parameterTypes;
    }
}
登入後複製

透過此方法,您現在可以等待任何事件類型:

await new MyClass().FromEvent("MyEvent");
登入後複製

此解決方案的優點

  • 支援具有任意數量或類型參數的任何事件類型。
  • 不需要將任務轉換為特定的回傳類型。
  • 無需建立多個不同類型和事件的 FromEvent 方法。

以上是如何使用通用 FromEvent 方法等待任何類型的任何事件?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板