这有危险吗?关于活动

时间:2009-07-21 12:19:09

标签: c# .net

也许是一个愚蠢的问题,但是......

在我的代码中,我在几个地方使用以下构造。

void MyFunction() 
{
    DoSomething(myClass.myProperty)

    myClass.PropertyChanged += (s,e ) => {
      if (e.PropertyName == "myProperty") {
        DoSomething(myClass.myProperty);
      }
    }
}

所以我想在最初做一些事情,并且在将来属性发生变化时也会这样做。

现在的问题是,MyFunction()在程序执行期间被多次调用。我将分配给PropertyChanged的代表是否会通过此方法添加evertime? (每次迭代消耗更多内存并减慢程序速度)或者编译器/运行时足够聪明,我应该只在第一次添加...?如果是这样,这是如何工作的?

2 个答案:

答案 0 :(得分:4)

编译器无法知道你的意图......它会在每次调用MyFunction()时忠实地附加事件处理程序。

以这种方式看待它们 - 它们的编译器无法知道函数中的引用变量(例如myclass)是指您之前附加处理程序的对象的相同实例。也不知道你没有在调用之间的其他地方分离处理程序。它无法做出这样的假设。

然而,您可以重构代码,以便处理程序只附加一次。由于其他消费者可能订阅PropertyChanged事件,因此您需要保留一些独立状态以了解您是否已订阅。例如:

if( !haveSubscribedToPropertyChanged ) {
    myClass.PropertyChanged += (s,e ) => {
          if (e.PropertyName == "myProperty") {
                DoSomething(myClass.myProperty);
          }
        }
        haveSubscribedToPropertyChanged = true;
      }

答案 1 :(得分:3)

许多其他答案建议您应检查PropertyChanged事件是否为null,以防止添加多个侦听器。该解决方案的一个问题是PropertyChanged可能是非null,如果代码的其他部分侦听同一事件但是另一个属性,如此。

void AnotherFunction() 
{
  myClass.PropertyChanged += (s,e) => {
    if (e.PropertyName == "anotherProperty") {
      DoSomethingElse(myClass.anotherProperty);
    }
  }
}

在我看来,更好的解决方案是维护一个最初为false的布尔标志,并且仅在调用MyFunction时设置为true。然后,检查此标志是否需要添加事件处理程序。