Общий метод FromEvent

Используя новую модель async / await it 'довольно просто генерироватьTask это завершается, когда происходит событие; вам просто нужно следовать этой схеме:

public class MyClass
{
    public event Action OnCompletion;
}

public static Task FromEvent(MyClass obj)
{
    TaskCompletionSource tcs = new TaskCompletionSource();

    obj.OnCompletion += () =>
        {
            tcs.SetResult(null);
        };

    return tcs.Task;
}

Это тогда позволяет:

await FromEvent(new MyClass());

Проблема в том, что вам нужно создать новыйFromEvent метод для каждого события в каждом классе, который вы хотели быawait на. Это может стать очень большим, очень быстрым, и этоВ основном это всего лишь шаблонный код.

В идеале я хотел бы иметь возможность сделать что-то вроде этого:

await FromEvent(new MyClass().OnCompletion);

Тогда я мог бы снова использовать тот жеFromEvent метод для любого события в любом случае. Я'Мы потратили некоторое время, пытаясь создать такой метод, и есть ряд препятствий. Для приведенного выше кода будет сгенерирована следующая ошибка:

Событие 'Namespace.MyClass.OnCompletion» может появляться только в левой части + = или - =

Насколько я могу сказать, там выигралЭто никогда не будет способом передачи такого события через код.

Итак, следующая лучшая вещь, казалось, пыталась передать имя события в виде строки:

await FromEvent(new MyClass(), "OnCompletion");

Это'не так идеален; ты нене получит intellisense и получит ошибку времени выполнения, если событие не 'не существует для этого типа, но он все еще может быть более полезным, чем тонны методов FromEvent.

Так что'достаточно легко использовать отражение иGetEvent(eventName) чтобы получитьEventInfo объект. Следующая проблема заключается в том, что делегат этого события неt известен (и должен иметь возможность изменяться) во время выполнения. Это затрудняет добавление обработчика событий, потому что нам нужно динамически создавать метод во время выполнения, сопоставляя данную сигнатуру (но игнорируя все параметры), которая обращается кTaskCompletionSource что у нас уже есть и устанавливает свой результат.

К счастью я нашелэта ссылка который содержит инструкции о том, как сделать [почти] именно черезReflection.Emit, Теперь проблема в том, что нам нужно излучать IL, и я понятия не имею, как получить доступ кtcs экземпляр у меня есть.

Ниже приведен прогресс, который ямы сделали для завершения этого:

public static Task FromEvent(this T obj, string eventName)
{
    var tcs = new TaskCompletionSource();
    var eventInfo = obj.GetType().GetEvent(eventName);

    Type eventDelegate = eventInfo.EventHandlerType;

    Type[] parameterTypes = GetDelegateParameterTypes(eventDelegate);
    DynamicMethod handler = new DynamicMethod("unnamed", null, parameterTypes);

    ILGenerator ilgen = handler.GetILGenerator();

    //TODO ilgen.Emit calls go here

    Delegate dEmitted = handler.CreateDelegate(eventDelegate);

    eventInfo.AddEventHandler(obj, dEmitted);

    return tcs.Task;
}

Какой ИЛ я мог бы испустить, что позволило бы мне установить результатTaskCompletionSource? Или, альтернативно, есть другой подход к созданию метода, который возвращает Задачу для любого произвольного события из произвольного типа?

Ответы на вопрос(3)

Ваш ответ на вопрос