只读WaitHandle C#

只读WaitHandle C#,c#,asynchronous,waithandle,C#,Asynchronous,Waithandle,我在负责在内部创建资源的对象的接口上公开了一个WaitHandle,但这可能需要很长时间。合同如下所示: public interface IHaveExpensiveResources { WaitHandle FinishedInitialization { get; } } WaitHandle启动unset,但我在初始化完成后(在后台,构造函数返回后)设置它。我不喜欢的一点是,此合同的消费者可以自己设置WaitHandle,而他们没有必要这样做。它让我想起了get-only属性

我在负责在内部创建资源的对象的接口上公开了一个
WaitHandle
,但这可能需要很长时间。合同如下所示:

public interface IHaveExpensiveResources {
    WaitHandle FinishedInitialization { get; }
}
WaitHandle
启动unset,但我在初始化完成后(在后台,构造函数返回后)设置它。我不喜欢的一点是,此合同的消费者可以自己设置
WaitHandle
,而他们没有必要这样做。它让我想起了get-only属性和get-only属性之间的区别

C语言中是否有类似于
WaitOnlyWaitHandle
的东西只公开了
WaitOne()
重载方法


因此,我不是XY问题的受害者,有没有一种更规范的方法来异步构造具有较长构造时间的对象?

您是否必须传回一个
WaitHandle
,或者您是否可以创建自己的包装类,只公开您想要的函数,类似于ReadOnlyCollection

一个选项是将WaitHandle包装到任务中(代码示例取自)

公共静态任务WaitOneAsync(此WaitHandle WaitHandle)
{
if(waitHandle==null)
抛出新ArgumentNullException(“waitHandle”);
var tcs=new TaskCompletionSource();
var rwh=ThreadPool.RegisterWaitForSingleObject(waitHandle,
委托{tcs.TrySetResult(true);},null,-1,true);
var t=tcs.Task;
t、 ContinueWith((先行项)=>rwh.Unregister(null));
返回t;
}

然后你只要调用
.WaitOneAsync()
任何
完成的初始化
都会返回并返回
任务

为了完整起见,这是我创建的接口和实现,用于在
WaitHandle上的
WaitOne()
重载方法上公开
WaitHandle

public interface IWaitOnlyWaitHandle
{
    bool WaitOne();
    bool WaitOne(TimeSpan timeout);
    bool WaitOne(int millisecondsTimeout);
    bool WaitOne(int millisecondsTimeout, bool exitContext);
    bool WaitOne(TimeSpan timeout, bool exitContext);
}

public sealed class WaitOnlyWaitHandle : IWaitOnlyWaitHandle
{
    # UPDATE: this object does not own the passed in WaitHandle
    private readonly WaitHandle _waitHandle;
    public WaitOnlyWaitHandle(WaitHandle waitHandle)
    {
        _waitHandle = waitHandle;
    }

    public bool WaitOne() => _waitHandle.WaitOne();
    public bool WaitOne(TimeSpan timeout) => _waitHandle.WaitOne(timeout);
    public bool WaitOne(int millisecondsTimeout) => _waitHandle.WaitOne(millisecondsTimeout);
    public bool WaitOne(int millisecondsTimeout, bool exitContext) => _waitHandle.WaitOne(millisecondsTimeout, exitContext);
    public bool WaitOne(TimeSpan timeout, bool exitContext) => _waitHandle.WaitOne(timeout, exitContext);
}

更新:根据@stevenbone的评论,此实现不拥有传递给构造函数的
WaitHandle
的生命周期。阅读他的评论了解更多信息。

您是否必须传回
WaitHandle
,或者您是否可以创建自己的包装类,只公开所需的函数,类似于使用+1来拥有包装类。顺便说一句,你有没有考虑过返回
Task
而不是
WaitHandle
的选项?@ScottChamberlain:是的,我可以创建一个真正包含
WaitHandle
的包装类,并创建我自己的契约。@alex.b我有,但我可以用构造函数来完成吗,还是需要工厂方法?我想我可以返回一个包装
WaitHandle.WaitOne()
方法调用的任务。谢谢你的回答,我会像Scott Chamberlain建议的那样创建一个包装类,也许我会创建一个工厂,这样我就有了TPL提供给你的特性,如果人们想使用它。一如既往,你的回答非常有启发性。非常感谢将IDisposable添加到IWaitOnlyWaitHandle界面并不能满足您的需求。我将从接口和包装器中删除IDisposable和Dispose()方法,从WaitHandle继承一个类,并向其中添加一个方法“public IWaitOnlyWaitHandle AsWaitOnly()”,该方法返回包装器-类似于List.AsReadOnly()所做的。在本地,您可以将其作为WaitHandle(设置和处置),并且可以向客户端提供真正的仅等待包装器。那么你就不必担心谁来管理waithandle的处理并防止误用了。@stevenbone也许可以在构造函数中创建wait句柄来防止同样的问题,只需较少的修改。如果是这样的话,你将如何设置或处理它?@stevenbone我认为你对它调用
Set
,但处理它的方式与处理样品的方式相同。不过,我认为您的答案是正确的(使用
AsWaitOnly()
)。我会更新答案。
public interface IWaitOnlyWaitHandle
{
    bool WaitOne();
    bool WaitOne(TimeSpan timeout);
    bool WaitOne(int millisecondsTimeout);
    bool WaitOne(int millisecondsTimeout, bool exitContext);
    bool WaitOne(TimeSpan timeout, bool exitContext);
}

public sealed class WaitOnlyWaitHandle : IWaitOnlyWaitHandle
{
    # UPDATE: this object does not own the passed in WaitHandle
    private readonly WaitHandle _waitHandle;
    public WaitOnlyWaitHandle(WaitHandle waitHandle)
    {
        _waitHandle = waitHandle;
    }

    public bool WaitOne() => _waitHandle.WaitOne();
    public bool WaitOne(TimeSpan timeout) => _waitHandle.WaitOne(timeout);
    public bool WaitOne(int millisecondsTimeout) => _waitHandle.WaitOne(millisecondsTimeout);
    public bool WaitOne(int millisecondsTimeout, bool exitContext) => _waitHandle.WaitOne(millisecondsTimeout, exitContext);
    public bool WaitOne(TimeSpan timeout, bool exitContext) => _waitHandle.WaitOne(timeout, exitContext);
}