C#学习笔记-事件

事件

  事件是类的一种成员,能够使类或对象具备通知能力。事件用于对象或类间的动作协调和信息传递。假设类A有某个事件,当这个事件发生时,类A会通知并传递事件参数(可选)给有订阅这个事件的类B,类B根据拿到的事件信息对事件进行响应处理。

事件模型

事件模型的5个组成部分:

  1、事件的拥有者(对象或类)

  2、事件成员(类成员)

  3、事件的响应者(对象或类)

  4、事件处理器(方法成员)

  5、事件订阅(关联事件和事件处理器),当用一个事件处理器订阅事件的时候,编译器会进行类型检查。事件和事件处理器需要遵守一个“约定”,“约定”约束了事件能够将何种消息传递给事件处理器,也约束着事件处理器能处理哪些消息。“约定”实际上指的就是委托。

  事件订阅解决了三个问题:

    1)事件发生时,事件的拥有者会通知哪些对象。

    2)使用什么样的事件处理器才能处理相应的事件。

    3)事件的响应者使用何种方法来处理事件。

//例1
class Program
{
    static void Main(string[] args)
    {
        Timer timer = new Timer();
        timer.Interval = 1000;
        Boy boy = new Boy();
        Girl girl = new Girl();
        timer.Elapsed += boy.Action;  //两个事件处理器订阅timer.Elapsed事件
        timer.Elapsed += girl.Action;
        timer.Start();
        Console.ReadLine();
    }
}

class Boy
{
    internal void Action(object sender, ElapsedEventArgs e)
    {
        Console.WriteLine("Jump!");
    }
}

class Girl
{
    internal void Action(object sender, ElapsedEventArgs e)
    {
        Console.WriteLine("Sing!");
    }
}
//例子2 事件的响应者和事件的拥有者是不同的对象
class Program
{
    static void Main(string[] args)
    {
        Form form = new Form();
        Controller controller = new Controller(form);
        form.ShowDialog();
    }
}

class Controller
{
    private Form form;
    public Controller(Form form)
    {
        if(form != null)
        {
            this.form = form;
            this.form.Click += this.FormClicked;
        }
    }

    private void FormClicked(object sender, EventArgs e)
    {
        this.form.Text = DateTime.Now.ToString();
    }
}
//例子3 事件的响应者和事件的拥有者是同一个对象
class Program
{
    static void Main(string[] args)
    {
        MyForm form = new MyForm();
        form.Click += form.Action;
        form.ShowDialog();

    }
}

class MyForm : Form 
{
    internal void Action(object sender, EventArgs e)
    {
        this.Text = DateTime.Now.ToString();
    }
}
//例子4 事件拥有者是事件的响应者的字段成员
class Pragram
{
    static void Main(string[] args)
    {
        MyForm form = new MyForm();
        form.ShowDialog();
    }
}

class MyForm : Form  //事件响应者
{
    private TextBox textBox;
    private Button button;  //事件拥有者

    public MyForm()
    {
        this.textBox = new TextBox();
        this.button = new Button();
        this.Controls.Add(textBox);
        this.Controls.Add(button);
        this.button.Click += this.ButtonClicked;  //订阅事件
        this.button.Text = "Say Hello";
        this.button.Top = 20;
    }

    private void ButtonClicked(object sender, EventArgs e)  //事件处理器
    {
        this.textBox.Text = "Hello World!";
    }
}

事件的声明

完整声明

  事件是基于委托的:

  1、事件需要委托类型来做约束(⭐⭐⭐);

  2、记录和保存事件处理器需要借助于委托;

  事件的本质是委托字段的包装器,对委托字段的访问起到限制作用,同时又对外界隐藏委托实例的大部分功能,仅对外暴露添加/移除事件处理器的功能

查看代码
 using System;
using System.Threading;

namespace Code
{
    class Program
    {
        static void Main(string[] args)
        {
            Customer customer = new Customer();
            Waiter waiter = new Waiter();
            customer.Order += waiter.Action;
            customer.Action();
            customer.PayTheBill();
        }
    }

    public class OrderEventArgs : EventArgs
    {
        public string DishName { get; set; }
        public string Size { get; set; }
    }

    //用于声明事件的委托,约束和存储事件处理器
    public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);

    public class Customer
    {
        private OrderEventHandler orderEventHandler;

        //声明事件
        public event OrderEventHandler Order
        {
            add
            {
                this.orderEventHandler += value;
            }

            remove
            {
                this.orderEventHandler -= value;
            }
        }

        public double Bill { get; set; }

        public void PayTheBill()
        {
            Console.WriteLine("Customer: I will Pay ${0}", this.Bill);
        }

        public void WalkIn()
        {
            Console.WriteLine("Walk into the restaurant");
        }

        public void SitDown()
        {
            Console.WriteLine("Sit Down.");
        }

        public void Think()
        {
            for (int i = 0; i < 5; ++i) {
                Console.WriteLine("Let me thinking...");
                Thread.Sleep(1000);
            }

            if(orderEventHandler != null)
            {
                OrderEventArgs e = new OrderEventArgs();
                e.DishName = "Kongpao Chicken";
                e.Size = "large";
                this.orderEventHandler.Invoke(this, e);
            }
        }

        public void Action()
        {
            Console.ReadLine();
            this.WalkIn();
            this.SitDown();
            this.Think();
        }
    }

    class Waiter
    {
        public void Action(Customer customer, OrderEventArgs e)
        {
            Console.WriteLine("Waiter: I will server you the dish -{0}.", e.DishName);
            double price = 10;
            if (e.Size == "small")
                price = price * 0.5;
            else if (e.Size == "large")
                price = price * 1.5;
            customer.Bill += price;
        }

    }
}

简略声明

事件的简易声明没有手动声明委托类型字段,那么事件处理器的引用存储在什么地方呢?答案是编译器会为事件准备委托类型字段存储事件处理器的引用,只不过被隐藏起来。

查看代码
 using System;
using System.Threading;

namespace Code
{
    class Program
    {
        static void Main(string[] args)
        {
            Customer customer = new Customer();
            Waiter waiter = new Waiter();
            customer.Order += waiter.Action;
            customer.Action();
            customer.PayTheBill();
        }
    }

    public class OrderEventArgs : EventArgs
    {
        public string DishName { get; set; }
        public string Size { get; set; }
    }

    //用于声明事件的委托,约束和存储事件处理器
    public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);

    public class Customer
    {
        public event OrderEventHandler Order;

        public double Bill { get; set; }

        public void PayTheBill()
        {
            Console.WriteLine("Customer: I will Pay ${0}", this.Bill);
        }

        public void WalkIn()
        {
            Console.WriteLine("Walk into the restaurant");
        }

        public void SitDown()
        {
            Console.WriteLine("Sit Down.");
        }

        public void Think()
        {
            for (int i = 0; i < 5; ++i) {
                Console.WriteLine("Let me thinking...");
                Thread.Sleep(1000);
            }

            if(this.Order != null)
            {
                OrderEventArgs e = new OrderEventArgs();
                e.DishName = "Kongpao Chicken";
                e.Size = "large";
                this.Order.Invoke(this, e);
            }
        }

        public void Action()
        {
            Console.ReadLine();
            this.WalkIn();
            this.SitDown();
            this.Think();
        }
    }

    class Waiter
    {
        public void Action(Customer customer, OrderEventArgs e)
        {
            Console.WriteLine("Waiter: I will server you the dish -{0}.", e.DishName);
            double price = 10;
            if (e.Size == "small")
                price = price * 0.5;
            else if (e.Size == "large")
                price = price * 1.5;
            customer.Bill += price;
        }

    }
}

声明事件的委托类型的命名约定

  声明Xxx事件的委托,命名为XxxEventHandler。委托的参数有两个,一个是object类型,参数名为sender——表示事件的拥有者。另一个是EventArgs的派生类,类名一般为XxxEventArgs,参数名为e。触发事件的方法名一般为OnXxx,访问级别为protected,否则会被外界任意使用,造成滥用。

查看代码
 using System;
using System.Threading;

namespace Code
{
    class Program
    {
        static void Main(string[] args)
        {
            Customer customer = new Customer();
            Waiter waiter = new Waiter();
            customer.Order += waiter.Action;
            customer.Action();
            customer.PayTheBill();
        }
    }

    public class OrderEventArgs : EventArgs
    {
        public string DishName { get; set; }
        public string Size { get; set; }
    }

    public class Customer
    {
        public event EventHandler Order;

        public double Bill { get; set; }

        public void PayTheBill()
        {
            Console.WriteLine("Customer: I will Pay ${0}", this.Bill);
        }

        public void WalkIn()
        {
            Console.WriteLine("Walk into the restaurant");
        }

        public void SitDown()
        {
            Console.WriteLine("Sit Down.");
        }

        public void Think()
        {
            for (int i = 0; i < 5; ++i) {
                Console.WriteLine("Let me thinking...");
                Thread.Sleep(1000);
            }

            this.OnOrder("Kongpao Chicken", "large");
        }

        protected void OnOrder(string dishName, string size)
        {
            if (this.Order != null)
            {
                OrderEventArgs e = new OrderEventArgs();
                e.DishName = dishName;
                e.Size = size;
                this.Order.Invoke(this, e);
            }
        }

        public void Action()
        {
            Console.ReadLine();
            this.WalkIn();
            this.SitDown();
            this.Think();
        }
    }

    class Waiter
    {
        public void Action(object sender, EventArgs e)
        {
            Customer customer = sender as Customer;
            OrderEventArgs orderInfo = e as OrderEventArgs;
            Console.WriteLine("Waiter: I will server you the dish -{0}.", orderInfo.DishName);
            double price = 10;
            if (orderInfo.Size == "small")
                price = price * 0.5;
            else if (orderInfo.Size == "large")
                price = price * 1.5;
            customer.Bill += price;
        }

    }
}
posted @   owmt  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示