C#复习笔记-事件

使用委托时,一般会出现两种角色,广播者和订阅者。广播者是包含委托字段的类型,它通过委托决定何时进行广播。订阅者是方法的接收者。它通过在广播者的委托上调用+=或者-=来决定何时开始监听何时结束监听。事件是一种使用委托的功能实现广播者或订阅者模型的结构。使用委托的主要目的是保证订阅者之间互不影响。声明事件的最简单的方法是在委托成员前面加上event关键字:

复制代码
//定义一个委托,接受2个decimal类型的参数
    public delegate void PirceChangedHandler(decimal oldPirce, decimal newPrice);

    public class Broadcaster
    {
        //定一个PirceChanged事件
        public event PirceChangedHandler PriceChanged;
        decimal _price;

        public decimal Price
        {
            get { return _price; }
            set
            {
                if (_price == value)
                    return;
                decimal oldprice = _price;
                _price = value;
                if (PriceChanged != null)
                    PriceChanged(oldprice, _price);
            }
        }
    }
复制代码

EventArgs是为事件传递信息的基类。我们可以继承EventArgs以便于在事件触发的时候传递值参数。EventArgs子类应当根据它包含的信息来命名,而非根据使用它的事件命名。一般将数据以属性或制度字段的方式暴露给外界。

1
2
3
4
5
6
7
8
9
10
11
public class PriceChangedEventArgs : EventArgs
{
    public readonly decimal Price;
    public readonly decimal OldPrice;
 
    public PriceChangedEventArgs(decimal price, decimal oldPrice)
    {
        Price = price;
        OldPrice = oldPrice;
    }
}

 定义了EvaenArgs子类以后,下一步就要定义事件的委托了,委托必须满足下面三个条件:

  • 委托必须以void作为返回值。
  • 委托必须接受两个参数。第一个参数是object类型,第二个参数是EventArgs子类。第一个参数表明了时间的广播者,第二个参数包含了需要传递的信息。
  • 委托的名称必须以EventHandler结尾。如下:
1
public delegate void PriceChangedEventHandler(object sender, PriceChangedEventArgs e);

框架定义了一个名为System.EventHandler<>的泛型委托也满足以上三个条件,事件模式还需要编写一个protected的虚方法来触发事件,方法名和时间名一致,以On为前缀,接收唯一的EvenArgs参数:

1
2
3
4
5
6
7
8
9
10
11
public class Stock
{
    public event EventHandler<PriceChangedEventArgs> PriceChanged;
    protected virtual void OnPriceChanged(PriceChangedEventArgs e)
    {
        var temp = PriceChanged;//为了多线程下可靠的工作,在测试和调用委托之前需要将他保存到零时变量
        if (temp != null)
            temp(this, e);
        PriceChanged?.Invoke(this, e);//也可以使用null条件运算符来避免声明临时变量,这种写法是最好的事件触发方式
    }
}

  完整的代码如下:

复制代码
    public class PriceChangedEventArgs : System.EventArgs
    {
        public readonly decimal LastPrice;
        public readonly decimal NewPrice;

        public PriceChangedEventArgs(decimal lastPrice, decimal newPrice)
        {
            LastPrice = lastPrice;
            NewPrice = newPrice;
        }
    }
    public class Stock
    {
        public event EventHandler<PriceChangedEventArgs> PriceChanged;
        protected virtual void OnPriceChanged(PriceChangedEventArgs e)
        {
            //为了多线程下可靠的工作,调用委托之前需要将他保存到零时变量
            //var temp = PriceChanged;
            //if (temp != null)
            //    temp(this, e);
            PriceChanged?.Invoke(this, e);//也可以这么写,线程安全又书写简单,是最好的触发方式。
        }

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

using App;

Stock stock = new Stock();
stock.Price = 20;
stock.PriceChanged += Stock_PriceChanged;

for (int i = 0; i < 10; i++)
{
    stock.Price = i + 20;
    Task.Delay(1000).Wait();
}

void Stock_PriceChanged(object? sender, PriceChangedEventArgs e)
{
    Console.WriteLine($"当前价格:{e.NewPrice},上一次的价格{e.LastPrice}");
}
Console.ReadKey();
复制代码

 

和方法一样,事件也可以重写,可以是虚的,抽象的密封的,静态的。

 

posted @   放羊娃  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
点击右上角即可分享
微信分享提示