明确地实现IAsyncResult
我一般都对部分实现接口持谨慎态度。 但是, IAsyncResult
有点特殊情况,因为它支持几种截然不同的使用模式。 使用/看到使用AsyncState
/ AsyncCallback
模式的AsyncState
是AsyncState
,而不是只使用AsyncWaitHandle
调用EndInvoke
,或者轮询IsCompleted
( AsyncWaitHandle
)?
相关问题: 检测ThreadPool WorkItem是否已完成/等待完成 。
考虑这个类(非常近似,需要锁定):
public class Concurrent { private ManualResetEvent _resetEvent; private T _result; public Concurrent(Func f) { ThreadPool.QueueUserWorkItem(_ => { _result = f(); IsCompleted = true; if (_resetEvent != null) _resetEvent.Set(); }); } public WaitHandle WaitHandle { get { if (_resetEvent == null) _resetEvent = new ManualResetEvent(IsCompleted); return _resetEvent; } public bool IsCompleted {get; private set;} ...
它有WaitHandle
(懒洋洋地创建,就像在IAsyncResult
文档中描述的那样)和IsCompleted
,但我没有看到AsyncState
的合理实现( {return null;}
?)。 那么它实现IAsyncResult
是否有意义? 请注意,Parallel Extensions库中的Task
确实实现了IAsyncResult
,但只隐式实现了IsCompleted
。
- 根据我的经验,只是在没有等待或首先被回调的情况下调用EndInvoke很少有用
- 仅提供回调有时是不够的,因为您的客户可能希望一次等待多个操作(WaitAny,WaitAll)
- 我从未对IsCompleted进行过调查,确实如此! 因此,您可以保存IsCompleted的实现,但它非常简单,似乎不值得让您的客户感到惊讶。
因此,异步可调用方法的合理实现应该真正提供完全实现的IAsyncResult。
顺便说一句,您通常不需要自己实现IAsyncResult,只需返回Delegate.BeginInvoke返回的内容即可。 有关示例,请参阅System.IO.Stream.BeginRead的实现。
看起来你有几个问题。 让我们分别处理它们
懒洋洋地创建WaitHandle
是的,这是最正确的方法。 你应该以线程安全的方式做到这一点,但懒惰是这样的。
但诀窍是处理WaitHandle。 WaitHandle是IDisposable的基础, 必须及时处理。 IAsycResult的文档不包括这种情况。 最好的方法是在EndInvoke中。 BeginInvoke的文档明确指出,对于每个BeginInvoke,必须有相应的EndInvoke(或BeginRead / EndRead)。 这是处理WaitHandle的最佳位置。
应该如何实现AsyncState?
如果你看一下返回IAsyncResult的标准BCL API,它们中的大多数采用一个状态参数。 这通常是从AsyncState返回的值(有关示例,请参阅Socket API)。 对于任何返回IAsyncResult的API BeginInvoke样式API,包含一个类型为对象的状态变量是一个好习惯。 没有必要,但良好的做法。
在状态变量的abscence中,返回null是可以接受的。
IsCompleted API
这将高度依赖于创建IAsyncResult的实现。 但是,是的,你应该实现它。