这里有一个小工具箱,包含六种方法,可用于将事件转换为任务:
public static Task EventToAsync(
Action<EventHandler> addHandler,
Action<EventHandler> removeHandler)
{
var tcs = new TaskCompletionSource<object>();
addHandler(Handler);
return tcs.Task;
void Handler(object sender, EventArgs e)
{
removeHandler(Handler);
tcs.SetResult(null);
}
}
public static Task<TEventArgs> EventToAsync<TEventArgs>(
Action<EventHandler<TEventArgs>> addHandler,
Action<EventHandler<TEventArgs>> removeHandler)
{
var tcs = new TaskCompletionSource<TEventArgs>();
addHandler(Handler);
return tcs.Task;
void Handler(object sender, TEventArgs e)
{
removeHandler(Handler);
tcs.SetResult(e);
}
}
public static Task<TEventArgs> EventToAsync<TDelegate, TEventArgs>(
Action<TDelegate> addHandler, Action<TDelegate> removeHandler)
{
var tcs = new TaskCompletionSource<TEventArgs>();
TDelegate handler = default;
Action<object, TEventArgs> genericHandler = (sender, e) =>
{
removeHandler(handler);
tcs.SetResult(e);
};
handler = (TDelegate)(object)genericHandler.GetType().GetMethod("Invoke")
.CreateDelegate(typeof(TDelegate), genericHandler);
addHandler(handler);
return tcs.Task;
}
public static Task EventToAsync(object target, string eventName)
{
var type = target.GetType();
var eventInfo = type.GetEvent(eventName);
if (eventInfo == null) throw new InvalidOperationException("Event not found.");
var tcs = new TaskCompletionSource<object>();
EventHandler handler = default;
handler = new EventHandler((sender, e) =>
{
eventInfo.RemoveEventHandler(target, handler);
tcs.SetResult(null);
});
eventInfo.AddEventHandler(target, handler);
return tcs.Task;
}
public static Task<TEventArgs> EventToAsync<TEventArgs>(
object target, string eventName)
{
var type = target.GetType();
var eventInfo = type.GetEvent(eventName);
if (eventInfo == null) throw new InvalidOperationException("Event not found.");
var tcs = new TaskCompletionSource<TEventArgs>();
EventHandler<TEventArgs> handler = default;
handler = new EventHandler<TEventArgs>((sender, e) =>
{
eventInfo.RemoveEventHandler(target, handler);
tcs.SetResult(e);
});
eventInfo.AddEventHandler(target, handler);
return tcs.Task;
}
public static Task<TArgument> EventActionToAsync<TArgument>(
Action<Action<TArgument>> addHandler,
Action<Action<TArgument>> removeHandler)
{
var tcs = new TaskCompletionSource<TArgument>();
addHandler(Handler);
return tcs.Task;
void Handler(TArgument arg)
{
removeHandler(Handler);
tcs.SetResult(arg);
}
}
所有这些方法都会创建一个
Task
,该任务将在关联事件的下一次调用时完成。此任务永远不会出现故障或被取消,它只能成功完成。
使用标准事件(
Progress<T>.ProgressChanged
)的示例:
var p = new Progress<int>();
int result = await EventToAsync<int>(
h => p.ProgressChanged += h, h => p.ProgressChanged -= h);
int result = await EventToAsync<EventHandler<int>, int>(
h => p.ProgressChanged += h, h => p.ProgressChanged -= h);
int result = await EventToAsync<int>(p, "ProgressChanged");
使用非标准事件的示例:
public static event Action<int> MyEvent;
int result = await EventActionToAsync<int>(h => MyEvent += h, h => MyEvent -= h);
当任务完成时,事件将取消订阅。没有提供早于此时间取消订阅的机制。