c# – 将事件转换为任务的可重用模式

前端之家收集整理的这篇文章主要介绍了c# – 将事件转换为任务的可重用模式前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我想要一个通用的可重用的代码片段为 wrapping EAP pattern as task,类似于 Task.Factory.FromAsyncBeginXXX/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" });
}

到目前为止,它看起来像这样:

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),而不需要反思?

解决方法

可以使用助手类和流畅的语法:
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<TEventHandler> unsubscribe,CancellationToken cancellationToken)
    {
        subscribe(_eventHandler);
        try
        {
            using(cancellationToken.Register(() => _completionSource.SetCanceled()))
            {
                action();
                return await _completionSource.Task;
            }
        }
        finally
        {
            unsubscribe(_eventHandler);
        }
    }
}

现在你有一个WithHandlerConversion帮助程序,它可以推断转换器参数的type参数,这意味着你只需要一次编写WebBrowserDocumentCompletedEventHandler.
用法

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);
原文链接:https://www.f2er.com/csharp/94395.html

猜你在找的C#相关文章