如何等待一个没有 return 任何东西但操作需要使用的数据的任务?

How to wait on a task which does not return anything but does manipulate data that needs to be used?

我是运行同步代码。但是,我需要从我使用的第三方库调用任务(因此无法控制它),并等待它完成。该任务没有 return 值,但它确实更新了作为参数传入的对象。

SerializaAsync 定义为

public async Task SerializeAsync(Type type, object value, Stream writeStream,
    CancellationToken cancellationToken)

我需要在任务完成后读取内存流。但是,由于任务没有 return Task,因此 GetAwaiter.GetResult() 无效。

所以我不能做的是

var result = resusmbResponseSerializer.SerializeAsync(
    typeof(CustomHttpResponse),
    smbDeliveryResponse,
    memoryStream, // pass a new MemoryStream() and task will update the stream with content
    CancellationToken.None).GetAwaiter().GetResult()

所以我尝试这样做。

string responseJson = null;
smbResponseSerializer.SerializeAsync(
    typeof(CusometHttpResponse),
    smbDeliveryResponse,
    memoryStream, // pass a new MemoryStream() and task will update the stream with content
    CancellationToken.None).GetAwaiter().OnCompleted(() =>
    {
        memoryStream.Seek(0, SeekOrigin.Begin);
        using (StreamReader sr = new StreamReader(ms))
        {
            responseJson = sr.ReadToEnd();
        }
    });

string readValue = responseJson; // this gets executed before the OnCompletedAction completes.

这不起作用,因为任务可能尚未完成并且尚未调用 onCompleted。因此readValue为null(当时的responseJson值)。

我可以使用 task.wait 等待任务,但我想避免 aggregateexception

有没有更好的方法等待这个任务完成,同步读取内存流?

如果您希望同步等待 Task,那么我建议您使用以下扩展方法:

public static class AsyncHelper
{
    private static readonly TaskFactory TaskFactory = 
        new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);

    public static void RunSync(this Func<Task> func)
        => TaskFactory
            .StartNew(func).Unwrap()
            .GetAwaiter().GetResult();
}

用法如下所示:

var serializeAsync = async () => 
     await resusmbResponseSerializer.SerializeAsync(
             typeof(CustomHttpResponse),
             smbDeliveryResponse,
             memoryStream,
             CancellationToken.None);

serializeAsync().RunSync();
//Process memorystream 

您仍然可以将 GetAwaiter().GetResult() 与非泛型 Task 一起使用,在这种情况下,GetResult 方法 returns void。所以你只需要从你的声明中删除 var result =:

resusmbResponseSerializer.SerializeAsync(typeof(CustomHttpResponse),
    smbDeliveryResponse, memoryStream, CancellationToken.None).GetAwaiter().GetResult()
// At this point the memoryStream has been updated

不可否认,GetResult 的方法 returns void 是非常规的。可能以这种方式命名是为了与通用 Task<TResult>.

保持一致