将传统的异步处理程序包装到 TPL 任务时<T>,回调和状态会发生什么?



此MSDN页面有以下示例:其目的是包装无法在各种Func<T1, T2, T3>重载中表示的APM样式任务。

static Task<String> ReturnTaskFromAsyncResult()
{
IAsyncResult ar = DoSomethingAsynchronously();     // <-- If this is an APM method, it's a bad example since most APM methods have a parameter for callback and state.
Task<String> t = Task<string>.Factory.FromAsync(ar, _ =>
{
return (string)ar.AsyncState;
});
return t;
}

我的问题与函数DoSomethingAsynchronously();有关。我看到的大多数APM函数都需要参数回调和状态,这在本示例中是缺失的。

问题:"DoSomethingAsynchronously"中的回调和状态参数发生了什么

我需要做什么才能正确地调用类似的函数?在我的情况下,我正在尝试像这样包装Azure表调用

Task CreateAsync(CloudTable tbl, CancellationToken token, object state)
{
ICancellableAsyncResult result = tbl.BeginCreate(null, state);  // Incorrect
token.Register((o) => result.Cancel(), state);
Task<bool> t = Task.Factory.FromAsync(result, _ =>
{
return (bool)result.AsyncState;
});
return t;
}
Task<bool> ExistsAsync(CloudTable tbl, CancellationToken token, object state)
{
ICancellableAsyncResult result = tbl.BeginExists(null, state);  // Incorrect
token.Register((o) => result.Cancel(), state);
Task<bool>  t = Task.Factory.FromAsync(result, _ =>
{
return (bool)result.AsyncState;
});
return t;
}

我想您误解了state参数的作用。它是为准备的:当您在其中传递对象时,您可以通过访问AsyncState来检索它。(类似于CancellationToken.Register()中的state。)在这种情况下,任何内容都不需要state,所以应该在其中传递null。这也意味着您创建的方法没有理由具有state参数。

callback参数用于异步操作完成时要执行的代码。你需要的FromAsync()的重载不使用这个,所以你也应该在那里传递null

您似乎也对在endMethod委托中放入什么感到困惑。顾名思义,您应该在其中调用EndXxx()方法(在您的情况下,是EndCreate()EndExists())。如果整个操作返回了一些东西,那么它实际上将由end方法返回,所以您应该从委托返回。然后,它将作为创建的Task的结果而可用。也可以在代理中执行一些清理。在你的情况下,我认为在那里处理注销登记是有意义的,因为它不再需要了。

所以,你的代码应该看起来像:

Task CreateAsync(CloudTable tbl, CancellationToken token)
{
ICancellableAsyncResult result = tbl.BeginCreate(null, null);
var cancellationRegistration = token.Register(result.Cancel);
return Task.Factory.FromAsync(result, ar =>
{
cancellationRegistration.Dispose();
tbl.EndCreate(ar);
});
}
Task<bool> ExistsAsync(CloudTable tbl, CancellationToken token)
{
ICancellableAsyncResult result = tbl.BeginExists(null, null);
var cancellationRegistration = token.Register(result.Cancel);
return Task.Factory.FromAsync(result, ar =>
{
cancellationRegistration.Dispose();
return tbl.EndExists(ar);
});
}

有关此主题的更多信息,请参阅Stephen Toub的任务和APM模式

最新更新