通用 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 方法等待任何類型的任何事件?的詳細內容。更多資訊請關注PHP中文網其他相關文章!