如果在VB.NET中不存在事件处理程序,则以编程方式添加事件处理程序

4

我正在尝试在ASP.NET网页中为多个控件使用单个事件处理程序。如果且仅当该事件处理程序不存在时,我希望在运行时添加事件处理程序。在C#中,我会按照下面的方式编写:

if (myTextBox.OnTextChanged == null)
{
    myTextBox.OnTextChanged += DoTextChangingValidation;
}

同样地,我知道我可以按照以下方式删除事件处理程序:
if (myTextBox.OnTextChanged != null)
{
    myTextBox.OnTextChanged -= DoTextChangingValidation;
}

我知道如何在Visual Basic中添加和删除事件处理程序...但是我该如何确定是否已经分配了事件处理程序?


你所编写的代码在C#中无法编译。在类的外部,你只能对事件执行两个操作:添加处理程序或删除处理程序。你无法获取处理程序列表,因此myTextBox.OnTextChanged不会返回委托表达式。鉴于此,在C#中你实际上正在做什么并不清楚,因此也不清楚你想在VB中做什么。 - Pavel Minaev
好的,所以我对于C#中可以做和不能做的事情有了误解。基本上我想要做的是防止同一个处理程序被多次添加到控件上。我想要确保在任何给定时间内,事件只能分配一个处理程序。 - Michael
2个回答

7

不管是在C#还是Visual Basic中,你都无法从对象外部进行此操作。一个事件基本上包含了两个访问器:addremove。如果你手动编写代码,这一点就会立即显现:

public event EventHandler Click
{
     add { ... }
     remove { ... }
}

这些方法被称为 add_Click(EventHandler)remove_Click(EventHandler)。即使您使用默认的事件实现,它们也会被自动创建。
public event EventHandler Click;

除了访问器是使用默认实现生成的私有多路广播委托字段来存储处理程序之外,它仍然没有任何区别,并且与事件具有相同的名称。

这意味着两件事:

  1. 对于类的客户端,关于事件唯一可以做的两件事情就是添加或删除处理程序,因为只有访问器是公开的。没有公开的访问器来列出当前注册的处理程序。

  2. 即使您使用事件的默认实现提供了一个字段,该字段仍然是私有的,所以除了在同一类的方法中访问它之外,无法访问它。如果您有代码权限,则可以使用反射,但请参见#1,了解为什么它不是通用解决方案。

实际上这是故意这样做的。原因是:对象可能是共享的,其他代码可能已经为其事件注册了处理程序。如果您获得处理程序列表的访问权限,您将能够自己调用它们,从而有可能违反合同并以所有者未曾预期的方式访问私有方法。

如果您需要这种功能,需要在提供事件的类中完成 - 要么编写自己的addremove以检查重复项,要么通过属性公开私有字段。


3

在这种情况下,您不需要在Visual Basic中进行检查。普通的删除语法已经足够聪明,如果它已经不存在,它不会向您抛出异常。


如果没有处理更多事件,.net是否应该抛出异常?你觉得呢? - Tony
1
@Tony - 如果你喜欢这种行为,你可以使用C#。但请注意它对C#程序员造成的问题 - 他们必须编写额外的代码,所有不正确(有缺陷)的实现等。 - Joel Coehoorn
当您尝试删除不存在的处理程序时,它会抛出一个空引用异常。 - Sebastien

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