为什么TaskFactory.FromAsync()重载需要提供状态对象

本文关键字:状态 对象 重载 TaskFactory FromAsync 为什么 | 更新日期: 2023-09-27 18:06:04

如TPL和Traditional.NET Framework异步编程MSDN文章以及Stephen Toub的Tasks和APM Pattern博客文章中所述,TaskFactory.FromAsync()TaskFactory<TResult>.FromAsync()方法可用于调整符合APM模式的Begin*((和End*((API,以便与Task Parallel Library一起使用。

下面我将只讨论TaskFactory<TResult>.FromAsync()过载,因为我的问题不取决于符合APM的API是否会产生值

有三种重载接受IAsyncResult对象,即:

  • FromAsync(IAsyncResult, Func<IAsyncResult, TResult>)
  • FromAsync(IAsyncResult, Func<IAsyncResult, TResult>, TaskCreationOptions)
  • FromAsync(IAsyncResult, Func<IAsyncResult, TResult>, TaskCreationOptions, TaskScheduler)

我理解这些API在Begin*((API方法除了AsyncCallback和状态object之外还需要三个以上参数的情况下很有用(例如,BeginXXXFromAsync的参数太多?(,或者当Begin*() API由于不采用状态object参数而不完全符合APM模式时(例如,如何将AsyncCTP与TFS APM方法(Query.Begin/EndQuery(一起使用?(。

我不明白的是,为什么剩余的过载(例如FromAsync(Func<AsyncCallback, Object, IAsyncResult>, Func<IAsyncResult, TResult>, Object)(都需要提供状态object。此状态object传递给Begin*() API,但在APM模式中,状态object供调用方专用。因此,FromAsync()object的状态传递给Begin*() API并不重要。

上面链接的MSDN文章有一个标题为"提供自定义状态数据"的部分,建议在延续委托中捕获任何所需的状态,并将状态对象的null传递给FromAsync()。然而,这并不能解释为什么FromAsync()方法需要给定一个状态对象。

当返回的Task<TResult>无法访问状态object时,为什么需要传递该状态?

为什么TaskFactory.FromAsync()重载需要提供状态对象

好吧,如果您遵循源代码,您可以看到确实可以使用Task.AsyncState:从Task实例访问状态

var task = Task.Factory.FromAsync<TResult>(...);
object state = task.AsyncState

此属性还保存其他场景中异步操作的状态,如Task.Factory.StartNew:

var task = Task.Factory.StartNew(_ => { }, "bar");
Console.WriteLine(task.AsyncState); // prints "bar"

因此,由于状态是可访问的,因此可以将状态作为参数传入,并且将API加倍一次使用状态参数和一次不使用状态参数听起来并不是更好的选择。尤其是当你刚好可以通过null的时候。