问题描述
我想有一个通用的可重复使用的一块$ C $下的,类似于 Task.Factory.FromAsync
做了的。
I'd like to have a generic reusable piece of code for wrapping EAP pattern as task, something similar to what Task.Factory.FromAsync
does for BeginXXX/EndXXX
APM pattern.
例如:
private async void Form1_Load(object sender, EventArgs e)
{
await TaskExt.FromEvent<EventArgs>(
handler => this.webBrowser.DocumentCompleted +=
new WebBrowserDocumentCompletedEventHandler(handler),
() => this.webBrowser.Navigate("about:blank"),
handler => this.webBrowser.DocumentCompleted -=
new WebBrowserDocumentCompletedEventHandler(handler),
CancellationToken.None);
this.webBrowser.Document.InvokeScript("setTimeout",
new[] { "document.body.style.backgroundColor = 'yellow'", "1" });
}
到目前为止,它看起来像这样:
So far, it looks like this:
public static class TaskExt
{
public static async Task<TEventArgs> FromEvent<TEventArgs>(
Action<EventHandler<TEventArgs>> registerEvent,
Action action,
Action<EventHandler<TEventArgs>> unregisterEvent,
CancellationToken token)
{
var tcs = new TaskCompletionSource<TEventArgs>();
EventHandler<TEventArgs> handler = (sender, args) =>
tcs.TrySetResult(args);
registerEvent(handler);
try
{
using (token.Register(() => tcs.SetCanceled()))
{
action();
return await tcs.Task;
}
}
finally
{
unregisterEvent(handler);
}
}
}
是否可以拿出类似的东西,它仍然会的不可以要求我输入 WebBrowserDocumentCompletedEventHandler
两次(用于 registerEvent
/ unregisterEvent
),而不是诉诸反射?
Is it possible to come up with something similar, which nevertheless would not require me to type WebBrowserDocumentCompletedEventHandler
twice (for registerEvent
/unregisterEvent
), without resorting to reflection?
推荐答案
这是可能的一个辅助类,并能说一口流利的语法:
It is possible with a helper class and a fluent-like syntax:
public static class TaskExt
{
public static EAPTask<TEventArgs, EventHandler<TEventArgs>> FromEvent<TEventArgs>()
{
var tcs = new TaskCompletionSource<TEventArgs>();
var handler = new EventHandler<TEventArgs>((s, e) => tcs.TrySetResult(e));
return new EAPTask<TEventArgs, EventHandler<TEventArgs>>(tcs, handler);
}
}
public sealed class EAPTask<TEventArgs, TEventHandler>
where TEventHandler : class
{
private readonly TaskCompletionSource<TEventArgs> _completionSource;
private readonly TEventHandler _eventHandler;
public EAPTask(
TaskCompletionSource<TEventArgs> completionSource,
TEventHandler eventHandler)
{
_completionSource = completionSource;
_eventHandler = eventHandler;
}
public EAPTask<TEventArgs, TOtherEventHandler> WithHandlerConversion<TOtherEventHandler>(
Converter<TEventHandler, TOtherEventHandler> converter)
where TOtherEventHandler : class
{
return new EAPTask<TEventArgs, TOtherEventHandler>(
_completionSource, converter(_eventHandler));
}
public async Task<TEventArgs> Start(
Action<TEventHandler> subscribe,
Action action,
Action<TEventHandler> unsubscribe,
CancellationToken cancellationToken)
{
subscribe(_eventHandler);
try
{
using(cancellationToken.Register(() => _completionSource.SetCanceled()))
{
action();
return await _completionSource.Task;
}
}
finally
{
unsubscribe(_eventHandler);
}
}
}
现在你有一个 WithHandlerConversion
的辅助方法,它可以从变频器的说法,这意味着你需要编写推断类型参数 WebBrowserDocumentCompletedEventHandler
只有一次。用法:
Now you have a WithHandlerConversion
helper method, which can infer type parameter from converter argument, which means you need to write WebBrowserDocumentCompletedEventHandler
only one time.Usage:
await TaskExt
.FromEvent<WebBrowserDocumentCompletedEventArgs>()
.WithHandlerConversion(handler => new WebBrowserDocumentCompletedEventHandler(handler))
.Start(
handler => this.webBrowser.DocumentCompleted += handler,
() => this.webBrowser.Navigate(@"about:blank"),
handler => this.webBrowser.DocumentCompleted -= handler,
CancellationToken.None);
这篇关于可重复使用的模式转换事件到任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!