ホームページ > バックエンド開発 > C++ > 汎用の FromEvent メソッドを使用して任意の型のイベントを待つにはどうすればよいですか?

汎用の FromEvent メソッドを使用して任意の型のイベントを待つにはどうすればよいですか?

Mary-Kate Olsen
リリース: 2024-12-31 22:38:19
オリジナル
914 人が閲覧しました

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

汎用 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");
ログイン後にコピー

このソリューションの利点

  • 任意の数またはタイプのパラメータを持つ任意のイベント タイプをサポートします。
  • はサポートしませんTask を特定の戻り値の型にキャストする必要があります。
  • 複数の FromEvent メソッドを作成する必要がなくなります。さまざまなタイプやイベントに対応します。

以上が汎用の FromEvent メソッドを使用して任意の型のイベントを待つにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート