我想有一个通用的可重用的代码包装EAP模式的任务,类似什么东西Task.Factory.FromAsync了呢BeginXXX/EndXXXAPM模式。
Task.Factory.FromAsync
BeginXXX/EndXXX
例如:
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" }); }
到目前为止,它看起来像这样:
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),而不是诉诸反射?
WebBrowserDocumentCompletedEventHandler
registerEvent
unregisterEvent
可以使用帮助器类和流利的语法:
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只需要编写一次即可。用法:
WithHandlerConversion
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);