首页 > 解决方案 > 使用 C# Task 进行事件异步操作

问题描述

假设我有一个SomeObj执行异步操作的对象,它已实现为返回一段数据的事件。

我可能有如下代码:

private void MyFunc1(Func<int> callback)
{
    SomeObj obj = SomeObj.GetSomeObj();
    obj.onAsyncComplete += callback;
}

因此,在此实现中,回调用于异步接受由 .int返回的结果数据 (an ) SomeObj.onAsyncComplete

我想将此假设示例移至使用asyncand await

private async int MyFunc1()
{
    SomeObj obj = SomeObj.GetSomeObj();
    Task<int> asyncCompleteTask = /* something with obj.onAsyncComplete */
    await asyncCompleteTask;
    return asyncCompleteTask.Result;
}

我将如何完成这样的事情?目标是能够await将结果int传递给onAsyncComplete事件。假设SomeObj不能修改。

标签: c#asynchronouseventstask

解决方案


有关 BART 链接的更多可见性:https ://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/interop-with-other-asynchronous-patterns-and-types#tasks-and-the -基于事件的异步模式 eap

我会考虑你为什么首先这样做,因为如果你正在实现另一个库,通常最好坚持他们想要的方法。但是,如果您正在为库创建类似包装器的东西并且真的想改变行为..我会创建一个扩展或包装器方法并使用TaskCompletionSource

MyFunc1可能看起来像这样:

public Task<int> MyFunc1()
{
    SomeObj someObj = new SomeObj();
    TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
    someObj.OnAsynComplete += (r) => tcs.SetResult(r);
    someObj.GetSomeObj();
    return tcs.Task;
}

或者你可以做一些扩展:

public static class SomeObjExtension
{
    public static Task<int> GetResultAsyncTask(this SomeObj someObj)
    {
        TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
        someObj.OnAsynComplete += (r) => tcs.SetResult(r);
        someObj.GetSomeObj();
        return tcs.Task;
    }
}


async void Main()
{
    SomeObj someObj = new SomeObj();
    int result = await someObj.GetResultAsyncTask();
    Console.WriteLine($"Got some number back: {result}");
}

如果您要在没有扩展的情况下运行它,它会遵循您指定的模式:

void Main()
{
    SomeObj someObj = new SomeObj();
    someObj.OnAsynComplete += (r) => Console.WriteLine($"Got some number back: {r}");
    someObj.GetSomeObj();
}

为了测试,我SomeObj这样创建:

public class SomeObj
{
    public void GetSomeObj()
    {
        Task.Run(async () => 
        {
            //do something...
            await Task.Delay(5000);
            OnAsynComplete?.Invoke(new Random().Next(1, 10000));
        });
    }
    public event OnAsyncCompleteHandler OnAsynComplete;
    public delegate void OnAsyncCompleteHandler(int result);
}

推荐阅读