Maison > développement back-end > C++ > Comment puis-je attendre n'importe quel événement sur n'importe quel type à l'aide d'une méthode FromEvent à usage général ?

Comment puis-je attendre n'importe quel événement sur n'importe quel type à l'aide d'une méthode FromEvent à usage général ?

Mary-Kate Olsen
Libérer: 2024-12-31 22:38:19
original
942 Les gens l'ont consulté

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

Méthode FromEvent à usage général

La méthode FromEvent originale nécessite la création de méthodes distinctes pour chaque événement et classe que vous souhaitez attendre. Pour éliminer le code passe-partout, les développeurs ont recherché une solution plus générale.

Une approche consiste à utiliser la réflexion pour récupérer l'événement et son type de délégué. Cependant, accéder aux paramètres du délégué et modifier TaskCompletionSource posait des défis.

Une solution personnalisée

Voici une solution personnalisée qui utilise les gestionnaires d'émissions et d'événements 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;
    }
}
Copier après la connexion

Avec cette méthode, vous pouvez désormais attendre n'importe quel événement sur n'importe quel tapez :

await new MyClass().FromEvent("MyEvent");
Copier après la connexion

Avantages de cette solution

  • Prend en charge tout type d'événement avec n'importe quel nombre ou type de paramètres.
  • Ne nécessitent de convertir la tâche en un type de retour spécifique.
  • Élimine le besoin de créer plusieurs méthodes FromEvent pour différents types et événements.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal