首页 > 编程语言 >C#学习笔记-事件

C#学习笔记-事件

时间:2024-07-06 19:08:49浏览次数:11  
标签:customer Console C# void 笔记 class 学习 事件 public

事件

  事件是类的一种成员,能够使类或对象具备通知能力。事件用于对象或类间的动作协调和信息传递。假设类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;
        }

    }
}

标签:customer,Console,C#,void,笔记,class,学习,事件,public
From: https://www.cnblogs.com/owmt/p/18194848

相关文章

  • POJ3017 Cut the Sequence
    POJ3017CuttheSequence题目大意给定一个一个长度为\(N\)的序列\(A\),要求把该序列划分成若干段,其中每一段中的数的和不大于\(M\),现在需要使得每一段中数的最大值的和最小,求该最小值。\[0\leqn\leq10^5\\0\leqm\leq10^{11}\\0\leqa_i\leq10^6\]解题思路......
  • CASS 11.0安装教程
    下载链接:https://fcnkteazjvur.feishu.cn/docx/Vz92dQpdAodmVmxq4qVcirdnnRe1.鼠标右键解压到“CASS11.0” 2.选中Setup,鼠标右键选择“以管理员身份运行”3.点击“自定义安装”4.选择软件安装路径,需要选择一下版本5.软件正在安装,请耐心等待6.点击“安装完成......
  • Lock4j简单的支持不同方案的高性能分布式锁实现及源码解析
    文章目录1.Lock4j是什么?1.1简介1.2项目地址1.3我之前手写的分布式锁和限流的实现2.特性3.如何使用3.1引入相关依赖3.2配置redis或zookeeper3.3使用方式3.3.1注解式自动式3.3.2手动式4.源码解析4.1项目目录4.2实现思路5.总结1.Lock4j是什么?1.1简介   ......
  • 使用c++实现图形化文件浏览
       代码中使用了SDL2库,需要先安装并正确配置相关的开发环境。还需要添加字体加载和处理的代码,为图方便,省略。#include<iostream>#include<SDL2/SDL.h>#include<SDL2/SDL_image.h>#include<vector>#include<string>#include<filesystem>constintSCREEN......
  • C++题解(3) 信息学奥赛一本通: 1013:温度表达转化 洛谷:B2013 温度表达转化 土豆编程:M
    【题目描述】利用公式 C=5×(F−32)÷9C=5×(F−32)÷9(其中CC表示摄氏温度,FF表示华氏温度)进行计算转化,输入华氏温度FF,输出摄氏温度CC,要求精确到小数点后55位。【输入】输入一行,包含一个实数FF,表示华氏温度。(F≥−459.67)(F≥−459.67)【输出】输出一行,包含一个......
  • ComfyUI进阶篇:ComfyUI核心节点(二)
    ComfyUI核心节点(二)前言:学习ComfyUI是一场持久战。当你掌握了ComfyUI的安装和运行之后,会发现大量五花八门的节点。面对各种各样的工作流和复杂的节点种类,可能会让人感到不知所措。在这篇文章中,我们将用通俗易懂的语言对ComfyUI的核心节点进行系统梳理,并详细解释每个参数。希望......
  • Web环境搭建phpstudy+pikachu靶场
    准备1、小皮面板(phpStudyv8.1版本)下载链接:https://www.xp.cn/download.html2、pikachu下载链接:https://github.com/zhuifengshaonianhanlu/pikachu配置步骤配置phpstudy1、解压phpstudy2、安装3、启动环境4、找到phpstudy当中,WWW目录5、解压pikachu,在WWW目录当中......
  • day01 初学c++第一章
    目录一、前置代码以及cout打印两条预处理代码:count打印语句:二、符号常量 三、标识符的命名规范四、数据类型 c++中整数类型的表现形式:在c++中,数字存在有符号和无符号之分的c++中实型的表现形式:代码所用函数:c++中字符型的表现形式:基础运算总结:转义字符c++中字......
  • EtherCAT转Profinet网关配置说明第一讲:配置软件安装及介绍
     网关XD-ECPNS20为EtherCAT转Profinet协议网关,使EtherCAT协议和Profinet协议两种工业实时以太网网络之间双向传输IO数据。适用于具有EtherCAT协议网络与Profinet协议网络跨越网络界限进行数据交换的解决方案。本网关通过上位机来进行配置。首先安装上位机软件一、上位机......
  • 小红书笔记没有热度没有流量是怎么回事?
    ​ 文末领取小红书电商开店运营教程!相信很多人做小红书开店,结果发布的笔记没有热度,没有流量,难以挣到钱小红书笔记没有热度没有流量可能是以下原因:1:发布违规内容小红书社区有明确的规范,禁止发布一些违规内容。如果你的笔记涉及违规内容,那么系统会对你的笔记进行限制曝光甚......