如何等待一个没有 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>
.
保持一致
我是运行同步代码。但是,我需要从我使用的第三方库调用任务(因此无法控制它),并等待它完成。该任务没有 return 值,但它确实更新了作为参数传入的对象。
SerializaAsync 定义为
public async Task SerializeAsync(Type type, object value, Stream writeStream,
CancellationToken cancellationToken)
我需要在任务完成后读取内存流。但是,由于任务没有 return Task
所以我不能做的是
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>
.