【问题标题】:How to write a Trigger?如何编写触发器?
【发布时间】:2011-08-22 20:37:48
【问题描述】:

我希望我的 C# 代码在为我的对象分配值时调用事件。

我究竟需要怎么做?

class MyClass {

  ManualResetEvent mre;

  public MyClass() {
    mre = new ManualResetEvent(false);
    Data = null;
  }

  public object Data { get; set; }

  void DataSet(object sender, EventArgs e) {
    Console.WriteLine("object Data has been set.");
    mre.Set();
  }

}

代表似乎不是我需要的。一个事件,也许?如果是这样,我将如何编写这样的事件?

MyClass mc;

void processA() {
  mc = new MyClass();
  mc.Data = GetDataFromLongProcess();
}

【问题讨论】:

    标签: c# multithreading events


    【解决方案1】:
    private object data;
    public object Data {
        get { return data;}
        set {
            if(value != data) {
                data = value;
                OnDataChanged();
            }
        }
    }
    protected virtual void OnDataChanged() {
        EventHandler handler = DataChanged;
        if(handler != null) handler(this, EventArgs.Empty);
    }
    public event EventHandler DataChanged;
    

    然后将任何代码挂接到DataChanged 事件。例如:

    MyClass mc = ...
    mc.DataChanged += delegate {
        Console.WriteLine("new data! wow!");
    };
    

    【讨论】:

    • 谢谢。我知道这很简单。我只是大脑受阻。
    • DataChanged 方法声明中需要更改哪些内容,以便我可以编写一个采用自定义数据类型的处理程序方法? (即if (handler != null) handler(this, new MyEventArgs(Data));(我已经写好了MyEventArgs类,只是不知道如何声明DataChanged方法来实现它。
    • @jp2code 可以声明为public event EventHandler<MyEventArgs> DataChanged;
    【解决方案2】:

    如果您想在设置属性时触发事件,您可以执行以下操作:

     public event Action OnDataChanged;
    
     protected object _data = null;
     public object Data
     {
         get { return _data; }
         set
         {
             _data = value;
             if(OnDataChanged != null)
                OnDataChanged();
         }
     }
    

    然后您只需将事件处理程序连接到您的对象,如下所示:

     mc = new MyClass();
     mc.OnDataChanged += delegate() { Console.WriteLine("It changed!"); };
     mc.Data = SomeValue();
    

    【讨论】:

    • 在大多数 C# 引用中,OnFoo调用名为 Fooevent 的方法(通常是 protected virtual),而不是事件本身的名称.当然,这只是惯例而不是规则。另请注意,严格来说,您应该在空检查之前将该字段捕获到变量中,以避免可能导致NullReferenceException 的线程边缘条件。
    • 好点。老实说,我还没有写足够多的事件来违反良好的惯例=D
    • 实际上,就 bindings 而言,有充分的理由遵循约定:PropertyDescriptor检查 名为 *Changed 的事件(不是On*Changed)并使用它来支持完整的数据绑定。这也适用于默认 PropertyDescriptor API 的任何其他用途。
    • @Marc 关于线程边缘条件的要点。您最终会遇到处理程序在分配后取消订阅的替代(尽管更容易处理)边缘条件。好在你所有的处理程序都是为了优雅地处理在这种情况下被调用的,对吧? :)
    • @dlev 是的,那个仍然存在 - 很痛苦,不是吗?
    【解决方案3】:

    我认为您使用基于事件的模型走在正确的轨道上。还可以看看观察者模式(据我所知,这是 .Net 委托和事件的基础):

    http://www.dofactory.com/Patterns/PatternObserver.aspx

    但最重要的是,正如迄今为止另一个有用的答案(Gravell 先生的实现)所表明的那样,您将必须有代码 IN setter 才能将其连接起来。唯一的选择是轮询更改的值,这对我来说很糟糕。

    【讨论】:

      【解决方案4】:

      您可以实现 INotifyPropertyChanged(这或多或少是一个事件),或者您可以将您的类作为一个 Action(触发器)并在属性更改时调用它。

      只是不要使用自动属性,而是使用具体的设置器并从那里调用您的事件/触发器。

      【讨论】:

        【解决方案5】:

        从概念上讲,您将在您的类中定义一个事件,在您的属性集块中,您将使用必要的参数调用该事件以确定刚刚发生的事情。

        【讨论】:

          【解决方案6】:
           public event SomeDelegateThatTakesIntAsParameter myEvent;
           void SetData(int data)
           {
             if(myEvent!= null)
               myEvent(data)
           }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2022-07-12
            • 1970-01-01
            • 1970-01-01
            • 2010-12-08
            • 2021-02-13
            相关资源
            最近更新 更多