首页 > 编程语言 >[C#] 事件和委托

[C#] 事件和委托

时间:2024-03-07 16:37:40浏览次数:11  
标签:Customer 委托 C# void public OrderEventArgs 事件 Order

事件 Event

事件模型的5个部分

事件的拥有者 (source, 对象) --> Customer

事件成员 (event, 成员) --> Order

声明

// 声明委托类型, 与类同级
// 参数1: 事件拥有者,或者说触发事件的对象,也就是顾客
// 参数2: 事件所携带的信息, 也就是点菜的内容
public delegate void OrderEventHandler(Customer c, OrderEventArgs e);

// Customer类里, 声明事件
class Customer 
{
    // 声明一个委托类型的字段, 且不能被外界访问
    private OrderEventHanlder orderEventHandler;
    public event OrderEventHandler Order 
    {
        // 添加事件
        add
        {
            this.orderEventHandler += value;
        }

        // 移除事件
        remove
        {
            this.orderEventHandler -= value;
        }
    }
    // ...
}

注意上面声明一个委托类型时, 第二个参数需要传入一些信息, c#有专门的类EventArgs来描述事件参数

// 事件参数, 事件所携带的信息
public class OrderEventArgs : EventArgs
{
    // 声明属性
    public string DishName { get; set; }
    public string Size { get; set; }
}

也可以进行简略声明(字段式声明 field-like)⬇️

public delegate void OrderEventHandler(Customer c, OrderEventArgs e);

// Customer类里就可以只写
class Customer 
{
    // 这时候的Order是一个委托字段
    public event OrderEventHandler Order;
    // ...
}

但是这样做是有隐患的, 因为其他的Customer类对象也可以在外部触发事件

就好比顾客1点了两盘菜, 结果结账的时候发现有别人给自己又点了两盆菜

c#为了避免这种情况, 加入了EventHandler委托(通用委托)
修改上面代码

// 首先去掉委托类型的声明
// public delegate void OrderEventHandler(Customer c, OrderEventArgs e);

// Customer类里就可以只写
class Customer 
{
    // 使用通用委托类型
    public event EventHandler Order;
    // ...
}

简化声明后, 后续代码引用事件时可以直接写事件名称Order, 而不是orderEventHandler

// 检查封装的委托是否为空
if (this.Order != null)

事件的本质是委托字段的包装器(封装), 仅对外暴露添加/移除事件处理器的功能(直接使用方法名)

事件的响应者 (event subscriber, 对象) --> Waiter

事件处理器 (event handler, 成员) - 一种回调方法 --> Waiter.Action

Waiter.Action方法作为事件处理器, 会被添加到事件中去
customer.Order += waiter.Action; // 为事件添加处理器

在我们使用通用的委托类型EventHandler之前, 这个方法接受两个参数

  • 参数1: 事件拥有者Customer
  • 参数2: 事件的参数类型OrderEventArgs

而当我们使用EventHandler之后, 即Waiter.Action方法将作为一个通用的委托类型(大概这个意思), 这时候参数应当符合类的定义
public void Action(object sender, EventArgs e)

  • 参数1: 发送/触发事件的任意对象
  • 参数2: 通用的事件的参数类型EventArgs

事件订阅 - 把事件处理器与事件关联在一起

全部代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace event_demo
{
    class Program
    {
        static void Main(string[] args)
        {
            Customer customer = new Customer();
            Waiter waiter = new Waiter();
            customer.Order += waiter.Action;  // 为事件添加处理器
            customer.Action();  // 触发事件, 同时也运行了事件处理器
            customer.PayBill(); // 
        }
    }

    // 事件类型, 事件参数
    public class OrderEventArgs : EventArgs
    {
        // 声明属性
        public string DishName { get; set; }
        public string Size { get; set; }
    }

    public class Customer
    {
        // 简化事件声明, Order就是事件的名字, 这是事件不是字段(注意), 不能用Invoke()了
        public event EventHandler Order;

        public double Bill { get; set; }
        public void PayBill()
        {
            Console.WriteLine("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("I'm thinking...");
                Thread.Sleep(1000);
            }

            // 触发Order事件, 传入参数
            this.OnOrder("Orange 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();
        }
    }

    public class Waiter
    {
        // 事件处理器, 通用版
        public void Action(object sender, EventArgs e)
        {
            // 将通用版转为本项目中定义好的类对象
            Customer c = sender as Customer;
            OrderEventArgs o = e as OrderEventArgs;
            Console.WriteLine("Serving the dish - {0}", o.DishName);
            double price = 35;
            switch (o.Size)
            {
                case "small":
                    price = price * 0.5;
                    break;
                case "large":
                    price = price * 1.5;
                    break;
                default:
                    break;
            }
            c.Bill += price;
        }
    }
}

标签:Customer,委托,C#,void,public,OrderEventArgs,事件,Order
From: https://www.cnblogs.com/Akira300000/p/18059188

相关文章

  • IfcMeasureValue
    IfcMeasureValueTypedefinitionNOTE DefinitionaccordingtoISO/CD10303-41:1992AmeasurevalueisavalueasdefinedinISO31-0(clause2).NOTE  IfcMeasureValue isaselectdatatypeformostbasicmeasuretypescomingfromISO10303-41.Selectitem......
  • 【Centroids】不一样的解法
    前言一道好题,也就花了我一个下午而已。本人做法比较清奇,可以当做开阔思路参考,并不太建议实操(太难调了!)。文章较啰嗦,谅解。思路众所周知,我并不太喜推式子,所以我们考虑直接根据题目限定的条件硬刚。首先,我们先假定\(1\)为根,并求出每个点的子树的大小,记为数组\(size\),并且再......
  • Navicat 无法连接Oracle / SQLserver
    报  cannotcreateocihandle cannotcreateocienviromentORA-XXXX等;排除用户名密码端口错误原因:Navicat本地的OCI版本与Oracle本地的不匹配查看Oracle本地的OCI版本,将Navicat升级至对应版本解决:下载新的oci进行替换https://www.oracle.com/database/technol......
  • [青少年CTF训练平台]web部分题解(已完结!)
    文章管理系统首先打开环境(>ω<。人)ZZz♪♪既然要做题,就要做全面了,图上说了,既然有假flag我就先找出来:假flag:打开vmware,使用sqlmap进行处理:sqlmap-uhttp://challenge.qsnctf.com:31645/?id=1--dbs记得中间的url换成自己的看到了六个可能:{*]ctftraining[*]information......
  • spring-webClient-响应式http客户端
    1.WebClient简介WebClient是SpringWebFlux模块提供的一个非阻塞的基于响应式编程的进行Http请求的客户端工具。WebFlux对标SpringMvc,WebClient相当于RestTemplate,同时也是Spring官方的Http请求工具。2.传统阻塞IO模型VS响应式IO模型传统阻塞IO模型RestTem......
  • css样式属性 使用汇总,补齐前端短板
    ---------------index.css常用网站css样式属性使用汇总1-------------/*先删除默认的内外边距*/*{margin:0;padding:0;}body{background-color:#fafafa;height:2000px;}li{list-style:none;/*取消li的符号*/}/*顶部导航栏开......
  • c#与java之间的区别盘点
    原文链接:http://www.mobiletrain.org/about/BBS/119467.htmlhttps://blog.csdn.net/clpig0125/article/details/50774628C#(CSharp)是Microsoft开发的一种面向对象的编程语言,而Java是由SunMicrosystems开发的一种面向对象的编程语言。虽然它们都是面向对象的编程语言,但它们之......
  • 若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版(文末见代码
    ​ 场景若依前后端分离版本地搭建开发环境并运行项目的教程:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108465662 CIMGitee地址:https://gitee.com/farsunset/cimCIM项目是基于mina或者netty框架下的推送系统,我们平常使用第三方的推送SDK,如极光推送,百度......
  • Scanner对象
    前言之前我们学的基本语法中我们并没有实现程序和人的交互,但是Java给我们提供了这样一个工具类,我们可以获取用户的输入。java.util.Scanner是Java5的新特征,我们可以通过scanner类来获取用户的输入基本语法代码Scannerstr=newScanner(System.in);通过Scan......
  • Spring-@ControllerAdvice-全局处理注解
    1,@ControllerAdvice介绍@ControllerAdvice是Spring框架提供的一个注解,用于定义全局的异常处理器和全局数据绑定。它通常用于集中处理应用程序中的异常,并提供统一的异常处理逻辑。2,@ControllerAdvice的基本使用packageorg.springframework.web.bind.annotation;importj......