.NET事件-阻止订阅者在事件上订阅

8
假设我有一个“Processor”接口,公开了一个事件-OnProcess。通常实现者会进行处理。因此,我可以安全地订阅这个事件,并确保它将被触发。但是有一个处理器不执行处理-因此我想防止订阅者订阅它。我能做到吗?换句话说,在下面的代码中,我想让最后一行抛出异常:
var emptyProcessor = new EmptyProcessor();
emptyProcessor.OnProcess += event_handler; // This line should throw an exception.

如果你被指派去找出代码崩溃的原因,你会在这一行寻找错误吗? - Dan Abramov
2个回答

8
class EmptyProcessor : IProcessor {

    [Obsolete("EmptyProcessor.OnProcess should not be directly accessed", true)]
    public event EventHandler OnProcess { 
        add { throw new NotImplementedException(" :( "); }
        remove { }
    }
}

在这种情况下,Obsolete 上的 true 参数会导致编译时异常。因此:
EmptyProcessor processor1 = new EmptyProcessor();
IProcessor processor2 = new EmptyProcessor();

processor1.OnProcess += handler;  // <-- compile-time error
processor2.OnProcess += handler;  // <-- run-time error

哇...我甚至不知道你可以做那个。我只是写了一个快速的样例应用程序来测试它,谁知道...它起作用了。非常有趣。 - Nick
+1,虽然我不确定这个异常信息会有多大帮助 ;) - Thomas Levesque
我同意这个想法有些粗糙。但是在BCL中甚至有很多使用NotSupportedException的情况...但我坚信,没有任何东西在所有情况下都被认为是“有害的”(不,即使是GOTO也不是)。 - Jimmy
“NotSupportedException”没问题。但仅仅订阅事件就会导致它,这几乎是无法猜测的。想象一下,如果这段代码通过库公开,那么事件订阅者怎么可能知道“+=”会抛出异常,特别是在通过接口处理类时? - Dan Abramov

0

你可以使用自定义的add/remove方法来实现它,但我认为这是一种不好的做法。

看,你有一个接口,一个由不同类实现的契约
OnProcess是这个契约的一部分,并没有任何特殊之处。

通常情况下,当你想要在相同的操作集下使用不同的类时,会使用接口。接口允许你像这样编码:

IProcessor proc = GetProcessorAnyhow ();
proc.DoSomething ();

在编译时不知道具体类型。

然而,采用您的方法,

IProcessor proc = GetProcessorAnyhow ();
proc.OnProcess += (sender, e) => { };

代码可能会在没有明显原因的情况下失败,尽管它看起来绝对是合法的代码。
始终确保错误的代码看起来是错误的

您可能已经犯了以下设计错误:

  • OnProcess放在IProcessor中,而实际上它可能不是每个处理器的契约
  • 使EmptyProcessor实现IProcessor,而实际上它无法满足契约

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接