c# - 是否可以限制 EventWaitHandle 的设置/重置?

标签 c# .net multithreading synchronization event-wait-handle

我想要一个 EventWaitHandle 对象(例如 ManualResetEvent),它只能从一个地方设置/重置,但可以从多个地方等待(使用 WaitOne())。换句话说,我只想有一个类可以设置/重置它,而所有其他类都可以对其调用 WaitOne() 。它有点像常规的“只读”属性:

private string MyReadOnlyText {get; private set;}

仅适用于ManualResetEvent中的特定方法。但不是:

private ManualResetEvent MyEvent {get; private set;}

当然,这是行不通的,因为虽然只有所有者类可以实例化此属性,但任何其他外部对象都可以使用 MyEvent.Set/MyEvent.Reset() 更改它。

这样的事情可能吗?这样做的目的是防止应用程序中的任意对象操纵等待句柄状态,并确保这可以从单个位置完成。

最佳答案

在某种程度上,这似乎可以通过约定来解决,即只需规定句柄应被消费者视为“只读”。对源代码进行简单的 grep 操作应该有助于防止恶意行为。

如果仅将对象公开为 WaitHandle,则对“仅实数”事件概念的支持有限。 WaitHandle 实例没有 Set() 方法,因此有助于提醒调用者不要搞乱它。

当然,调用者仍然可以将其转换为其实际类型,并且 WaitHandle 中有仍然允许操作的静态方法。所以这并不是100%的保证。但这会有所帮助(并在您进行代码审核时提供更独特的 grep 模式)。

最后,评论中提到的“包装器”方法也可以工作。这是最强大的,对于任何类型的“限制对除所有者对象之外的成员的访问”来说都是相对常见的模式。

如果调用者与特权代码位于不同的程序集中,那么最简单的方法是将隐藏内容设置为“内部”,将公共(public)内容设置为“公共(public)”。如果它们位于同一个程序集中,那么如果您可以将隐藏成员与特权代码放在同一个类中,那么它们当然可以只是该类的私有(private)成员。

但通常,您希望将特殊可访问性对象封装为一个单独的类,同时仍然授予对一个特定类的特权访问权限并限制其他所有人的访问权限。在这种情况下,您可以使用嵌套类来实现这种分离,外部类包含特权代码,嵌套类包含隐藏代码。

此方法的一个版本使用基/子类设计,其中基类具有公共(public)成员,子类具有隐藏代码:

class A
{
    public class B
    {
        protected ManualResetEvent _event = new ManualResetEvent(false);

        public void Wait() { _event.Wait(); }
    }

    private class C : B
    {
        public void Set() { _event.Set(); }
    }

    public B GetAnInstanceofB() { return new C(); }

    private void DoSomethingWithB(B b) { ((C)b).Set(); }
}

现在调用者可以在返回的实例上调用 B.Wait(),但他们无法转换为 C 类型来访问 Set( ) 方法。但请注意,A 类中的代码是允许的(因为它可以将类型强制转换为 C)。

请注意,类 B 本身不需要嵌套。只需C

此主题的另一个变体是声明一个仅包含公共(public)方法的接口(interface),然后拥有该接口(interface)的单个​​实现者。同样,实现类将嵌套为特权代码私有(private),而接口(interface)可以嵌套也可以不嵌套。

最后请注意,所有这些都是代码可靠性和维护的问题。当然,代码总是可以使用反射来检查和访问它想要的任何类型的任何部分。

归根结底,您必须考虑代码的受众。如果这是一个小团队,并且代码完全独立于一个项目,那么只需告诉每个人“你可以等待这个,但不要破坏这个事件”就足够了。在更大的环境中,也许多个团队一起处理多个相关项目,但基本上仍然是一个独立的单元,使用 WaitHandle 可能就足够了。如果您正在编写一个打算广泛使用的库,那么封装和私有(private)成员和类是一个很好的工具。 :)

关于c# - 是否可以限制 EventWaitHandle 的设置/重置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26538012/

相关文章:

c# - 使用存储在 session 中的 Guid 过滤 Linq

c# - 如何在 Entity Framework 5 代码中映射标识关系第一个子实体与多个互斥父实体

c# - 为什么不针对字段优化简单属性?

c++ - 在线程中更改 Windows 窗体控件

Java 线程似乎运行多次

performance - 有人用过谷歌性能工具吗?

c# - ProgressBar 的默认前景色

c# - Visual Studio 忽略了我在 ASP.net 项目中的语法错误

c# - 如何将选中列表框中的项目灰显

c# - 在 .dotnet (c#) 中,如果没有任何订阅,是否仍会引发事件?