c# - 委托(delegate),我不明白的事件约定

标签 c# events delegates

我从 C# in nutshell 书中看到了这个例子 ( http://www.albahari.com/nutshell/ch04.aspx )

using System;

public class PriceChangedEventArgs : EventArgs
{
  public readonly decimal LastPrice;
  public readonly decimal NewPrice;

  public PriceChangedEventArgs (decimal lastPrice, decimal newPrice)
  {
    LastPrice = lastPrice; NewPrice = newPrice;
  }
}

public class Stock
{
  string symbol;
  decimal price;

  public Stock (string symbol) {this.symbol = symbol;}

  public event EventHandler<PriceChangedEventArgs> PriceChanged;

  ****protected virtual void OnPriceChanged (PriceChangedEventArgs e)
  {
    if (PriceChanged != null) PriceChanged (this, e);
  }****

  public decimal Price
  {
    get { return price; }
    set
    {
      if (price == value) return;
      OnPriceChanged (new PriceChangedEventArgs (price, value));
      price = value;
    }  
  }
}

class Test
{
  static void Main()
  {
    Stock stock = new Stock ("THPW");
    stock.Price = 27.10M;
    // register with the PriceChanged event    
    stock.PriceChanged += stock_PriceChanged;
    stock.Price = 31.59M;
  }

  static void stock_PriceChanged (object sender, PriceChangedEventArgs e)
  {
    if ((e.NewPrice - e.LastPrice) / e.LastPrice > 0.1M)
      Console.WriteLine ("Alert, 10% stock price increase!");
  }
}

我不明白的是为什么要使用这个约定......

  ****protected virtual void OnPriceChanged (PriceChangedEventArgs e)
  {
    if (PriceChanged != null) PriceChanged (this, e);
  }****

为什么我需要那个方法,为什么我要给它“这个”参数?!?我不能直接在测试类中使用方法 PriceChanged 附加该类的事件并跳过该方法吗?!?

最佳答案

您需要 null 检查,因为在有人订阅之前事件将为 null。如果直接引发它并且它​​为 null,则会抛出异常。

此方法用于引发 事件,而不是订阅事件。您可以轻松订阅另一个类(class)的事件:

yourObject.PriceChanged += someMethodWithTheAppropriateSignature;

但是,当您想让事件“触发”时,类需要引发该事件。 “this”参数提供 sender EventHandler<T> 中的参数.按照惯例,用于事件的委托(delegate)有两个参数,第一个是object sender。 ,它应该是引发事件的对象。第二个是EventArgsEventArgs 的子类,它提供特定于该事件的信息。该方法用于正确检查 null 并使用适当的信息引发事件。

在这种情况下,您的事件声明为:

public event EventHandler<PriceChangedEventArgs> PriceChanged;

EventHandler<PriceChangedEventArgs>是具有以下签名的委托(delegate):

public delegate void EventHandler<T>(object sender, T args) where T : EventArgs

这意味着必须使用两个参数引发事件 - 一个对象(发送者或“this”)和一个 PriceChangedEventArgs 的实例.

话虽这么说,这个约定实际上并不是引发事件的“最佳”方式。实际上使用会更好:

protected virtual void OnPriceChanged (PriceChangedEventArgs e)
{
    var eventHandler = this.PriceChanged;
    if (eventHandler != null) 
        eventHandler(this, e);
}

这可以在多线程场景中为您提供保护,因为如果您有多个线程在运行,单个订阅实际上可能会在空检查和加注之间取消订阅。

关于c# - 委托(delegate),我不明白的事件约定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8672476/

相关文章:

JavaScript:在 Firefox for Android 上跟踪选择更改

c# - 存储对非静态方法的引用

c# - 将动态数据类型传递给函数

javascript - Vue - 获取没有(事件)的元素调用函数

javascript - 检测鼠标点击位置

c# - 是否可以同步调用异步调用?

c# - 无法将 lambda 表达式转换为类型 'System.Delegate' 因为它不是委托(delegate)类型?

c# - ASP.NET,剑道用户界面,CS1660 : Cannot convert lambda expression to type 'string'

c# - 初始化资源并销毁它直到另一个线程需要它

c# - Windows 窗体启动另一个窗体