汎用 FromEvent メソッド
元の FromEvent メソッドでは、待機するイベントとクラスごとに個別のメソッドを作成する必要があります。ボイラープレート コードを排除するために、開発者はより汎用的なソリューションを模索しました。
アプローチの 1 つは、リフレクションを使用してイベントとそのデリゲート タイプを取得することです。ただし、デリゲートのパラメーターにアクセスし、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; } }
このメソッドを使用すると、任意のイベントを待機できるようになります。 type:
await new MyClass().FromEvent("MyEvent");
このソリューションの利点
以上が汎用の FromEvent メソッドを使用して任意の型のイベントを待つにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。