C#【进阶】委托和事件

委托和事件

在这里插入图片描述

文章目录

      • 1、委托
        • 1、委托概念
        • 2、基本语法
        • 3、定义自定义委托
        • 4、使用自定义委托
        • 5、委托变量可以存储多个函数
        • 6、系统定义好的委托
          • 思考 怪物死亡数据更新
      • 2、事件
        • 1、事件概念
        • 2、事件的使用
        • 3、为什么有事件
          • 思考 热水器
      • 3、匿名函数
        • 1、匿名函数概念
        • 2、基本语法
        • 3、使用
        • 4、匿名函数的缺点
          • 思考 匿名函数作为返回值
      • 4、Lambad表达式
        • 1、Lambad表达式概念
        • 2、lambad表达式语法
        • 3、使用
        • 4、闭包

1、委托

1、委托概念
委托是方法的容器,表示方法的变量类型
用来存储、传递方法
委托的本质是一个类,用来定义方法的类型(返回值和参数的类型)
不同的方法必须对应和各自格式一致的委托
2、基本语法
访问修饰符 delegate 返回值 委托名(参数列表);
3、定义自定义委托
访问修饰符不写默认为public
    声明了一个可以用来存储无参无返回值函数的容器
    delegate void MyFun();
    //表示用来装载或传递返回值为int有一个int参数的函数委托
    delegate int MyFu2(int x);
4、使用自定义委托
委托变量是函数的容器
    委托常用在:
    1、作为类的成员
    2、作为函数的参数
    
    static void Fun()
    {
        Console.WriteLine("aaa");
    }
    //声明委托方法1、将Fun()方法存到MyFun委托容器中
    MyFun f = new MyFun(Fun);
    //方法1、调用委托
    f.Invoke();
    f();
    //声明委托方法2、声明委托变量f2存储Fun()方法
    MyFun f2 = Fun;
    //方法2、调用委托
    f2();
    f2.Invoke();

    static int Fun2(int value)
    {
        return value;
    }

    MyFun2 f3 = Fun2;
    Console.WriteLine(f3(1));

    MyFun2 f4 = new MyFun2(Fun2);
    Console.WriteLine(f4.Invoke(3));

//声明委托
delegate void MyFun();
//表示用来装载或传递返回值为int有一个int参数的函数委托
delegate int MyFun2(int x);
5、委托变量可以存储多个函数
增加函数
    MyFun ff = Fun;
    ff += Fun;
    ff();

    class test{
    	MyFun fun;
        MyFun2 fun2;
	
    	public void AddFun(MyFun fun, MyFun2 fun2){
            this.fun += fun;
            this.fun2 += fun2;
        }
	}
移除函数
    ff -= Fun;
	//清空
	ff = null;
	if(ff!=null){
        ff();
    }
6、系统定义好的委托
无参无返回值 // Action
Action action = Fun;
有参无返回值 // Action<>
Action<int,string> action2 = Fun;
指定返回值类型	// Func<>
Func<string> func = Fun;
有参数有返回值 //Func<参数,返回值>
Func<int,int> func = Fun;
思考 怪物死亡数据更新
//怪物死亡后,玩家要加10元钱,界面要更新数据
//成就要累加怪物击杀数,用委托实现这些功能

Monster monster = new Monster();
Player player = new Player();
Panel panel = new Panel();
ChengJiu chengJiu = new ChengJiu();

//委托关联
monster.deadDoSomthing += player.MonsterDeadDoSomthing;
monster.deadDoSomthing += panel.MonsterDeadDoSomthing;
monster.deadDoSomthing += chengJiu.MonsterDeadDoSomthing;
monster.Dead();

class Monster
{
    //声明委托
    public Action<Monster> deadDoSomthing;
    public int money;
    public void Dead()
    {
        Random random = new Random();
        money = random.Next(15, 21);
        Console.WriteLine("怪物死亡");
        //使用委托 这里的this是将自己作为参数传出去
        if (deadDoSomthing != null) {  deadDoSomthing(this); }
        deadDoSomthing = null;
    }
}
class Player
{
    private int myMoney = 0;
    public void MonsterDeadDoSomthing(Monster m)
    {
        myMoney += m.money;
        Console.WriteLine("击杀获得{0}金币" , m.money);
        Console.WriteLine("余额"+myMoney);
        
    }
}
class Panel
{
    private int nowShowMoney = 0;
    public void MonsterDeadDoSomthing(Monster m)
    {
        nowShowMoney += m.money;
        Console.WriteLine("显示余额" + nowShowMoney);
    }
}

class ChengJiu
{
    private int nowKillMonsterNum = 0;
    public void MonsterDeadDoSomthing(Monster m)
    {
        nowKillMonsterNum++;
        Console.WriteLine("击杀数量" + nowKillMonsterNum);
    }
}

2、事件

1、事件概念
事件是基于委托的存在
事件是委托的安全包裹
让委托的使用更具有安全性
事件是一种特殊的变量类型
2、事件的使用
声明语法:
	访问修饰符 event 委托类型 事件名;
事件的使用:
	1、事件是作为成员变量存在于类中
	2、委托怎么用,事件就怎么用
事件相对于委托的区别:
	1、不能在类外部赋值,但可以加减
	2、不能在类外部调用
注意:
	它只能作为成员存在于类、接口以及结构体中
    不能作为临时变量
    
Test test = new Test();
class Test
{
    //委托成员变量,用于存储函数
    public Action myFunc;
    //事件成员变量,用于存储函数
    public event Action myEvent;
    
    public Test()
    {
        myFunc = TestFunc;
        myFunc += TestFunc;

        myEvent = TestFunc;
        myEvent += TestFunc;
        myEvent();
        myEvent.Invoke();
        myEvent = null;
    }
    public void TestFunc(){}
}
3、为什么有事件
1、防止外部随意置空委托
2、防止外部随意调用委托
3、事件相当于对委托进行了一次封装,让其更加安全
思考 热水器
//有一个热水器,包含一个加热器,一个报警器,一个显示器
//我们给热水通上电,当水温超过95度时
//1、报警器会开始发出语音,告诉你水温
//2、显示器也会改变水温提示,提示水已经烧开

Heater h = new Heater();
Alarm alarm = new Alarm();
Display display = new Display();

h.myEvent += alarm.ShowInfo;
h.myEvent += display.ShowInfo;
h.AddHot();
class Heater
{
    public event Action<int> myEvent;
    private int temperature = 25;
    public void AddHot()
    {
         int updateIndex= 0;
        while (true)
        {
            if (updateIndex % 9999999 == 0)
            {
                temperature++;
                Console.WriteLine("温度计"+temperature);
                if (temperature >= 95)
                {
                    if (myEvent!=null)
                    {
                        myEvent(temperature);
                    }
                    myEvent = null;
                }
                if (temperature >=100)
                {
                    break;
                }
                updateIndex = 0;
            }
            updateIndex++;
        }
    }
}
class Alarm
{
    public void ShowInfo(int v)
    {
        Console.WriteLine("滴滴,温度" + v);
    }
}
class Display
{
    public void ShowInfo(int v)
    {
        Console.WriteLine("显示温度" + v);
    }
}

3、匿名函数

1、匿名函数概念
配合委托和事件使用
脱离委托和事件,是不会使用匿名函数的
2、基本语法
delegate(参数列表){函数逻辑};
何时使用
	1、函数中传递委托参数时
	2、委托或事件赋值时
3、使用
//1、无参无返回值
Action action = delegate ()
{
    Console.WriteLine("匿名函数");
};
action();
//2、有参
Action<int,string> b = delegate (int a, string b)
{
    Console.WriteLine(a);
    Console.WriteLine(b);
};
b(1,"a");
//3、有返回值
Func<string> c = delegate ()
{
    return "a";
};
Console.WriteLine(c());
//4、一般情况会作为函数参数传递,或者作为函数返回值
Test t = new Test();
//参数传递
t.Do(1, delegate () { Console.WriteLine("随参数传入的匿名函数逻辑"); });
//返回值
Action ac = t.GetFun();
ac();
//直接调用返回的委托函数
t.GetFun()();
class Test
{
    public Action action;
    //作为参数传递时
    public void Do(int a , Action fun)
    {
        Console.WriteLine(a);
        fun();
    }
    //作为返回值
    public Action GetFun()
    {
        return delegate () { Console.WriteLine("函数内部返回的一个匿名函数逻辑"); };
    }
}
4、匿名函数的缺点
添加到委托或事件容器中后,不记录无法单独移除
思考 匿名函数作为返回值
//写一个函数传入一个整数,返回一个函数
//之后执行这个匿名函数时传入一个整数和之前那个函数传入的数相乘
//返回结果
Func<int, int> func = TestFunc(2);
Console.WriteLine(func(3));
Func<int, int> TestFunc(int i)
{
    //会改变i的生命周期
    return delegate(int v) {
        return i * v; 
    };
}

4、Lambad表达式

1、Lambad表达式概念

匿名函数的简写

2、lambad表达式语法
(参数列表) =>{};
3、使用
//1、无参无返回值
Action a = () =>
{
    Console.WriteLine("无参无返回值");
};
a();
//2、有参无返回值
Action<int> a2 = (int value) =>
{
    Console.WriteLine("有参无返回值" + value);
};
a2(2);
//3、省略参数类型,参数类型和委托或事件容器一致
Action<int> a3 = (value) =>
{
    Console.WriteLine("省略参数写法" + value);
};
a3(3);
//有参有返回值
Func<string, int> a4 = (value) =>
{
    Console.WriteLine("有参有返回值lambad" + value);
    return 1;
};
Console.WriteLine(a4("a"));
4、闭包
内层函数可以引用包含在它外层函数的变量
即使外层函数的执行已经终止
注意:
	该变量提供的值并非变量创建时的值,而是在父函数范围内的最终值
    
Test t = new Test();
t.DoAction();
class Test
{
    public event Action action;
    public Test()
    {
        //闭包
        int value =10;
        action = () =>
        {
            Console.WriteLine("闭包的值"+value);
        };

        for (int i = 0; i < 10; i++)
        {
            //每次循环的index不一样,此非彼
            int index = i;
            action += () =>
            {
                Console.WriteLine();
                Console.WriteLine("假循环"+i);//最终值
                Console.WriteLine("真循环" + index);
            };
        }
    }
    public void DoAction()
    {
        action();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/630227.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

电工能混到这份上

最近看到某电工师傅发了一篇帖子&#xff0c;大致内容是他在处理一个简单故障的时候居然花了很长的时间。我们一起来看看他遇到的是什么故障吧! plc 控制的一台设备&#xff0c;行走部分靠 2 个脚踏开关控制&#xff08;内部开关量控制方向&#xff0c;电位器控制速度&#xff…

jspXMl标记语言基础

1.打开命令框进入数据库 打开eclipse创建需要连接的项目 粘贴驱动程序 查看驱动器 使用sql的包 int代表个 conlm代表列名 <%page import"java.sql.ResultSet"%> <%page import"java.sql.Statement"%> <%page import"java.sql.Connect…

fl studio试用版文件保存无法打开??一个方法教你免费打开!

前言 当下&#xff0c;各款编曲软件五花八门&#xff0c;而这其中最有声誉的必为FL Studio莫属 这个软件呢国人习惯叫他水果&#xff0c;拥有强大的录音、编曲、混音等功能&#xff0c;所以广受音乐圈欢迎。如今&#xff0c;大部分水果一旦有编曲所需&#xff0c;一般都要使用…

阿里云 服务之前设置的密钥登陆,关闭了密码登录,现在打开密码登录

通过网页远程链接 切换用户 sudo -i 输入vim /etc/ssh/sshd_config 进入配置文件 找到 将这一项设置为yes 重启系统 systemctl restart sshd.service

std::remove-----std::remove_if

std::remove和std::remove_if 是 C11 标准库中的一个算法函数. std::remove 作用 遍历一遍容器&#xff0c;将容器中所有不是指定元素的元素往前复制。 总之就是一句话&#xff1a; 把不该删除的移动到前面&#xff0c;后面的就是应该删除的。 注意&#xff1a; 1&#…

汇聚荣科技:拼多多上架商品后需要做页面推广吗?

在电商平台上&#xff0c;商品的曝光率和销量往往成正比。那么&#xff0c;当您在拼多多上架了新品&#xff0c;是不是就意味着坐等订单呢?答案显然是否定的。商品一旦上架&#xff0c;接下来需要做的就是通过有效的页面推广来增加商品的可见度&#xff0c;吸引潜在买家的注意…

Golang RPC实现-day02

导航 Golang RPC实现一、客户端异步并发多个请求1、 客户端结构体2、 一个客户端&#xff0c;异步发送多个请求&#xff0c;使用call结构体代表客户端的每次请求3、客户端并发多个请求4、客户端接收请求 Golang RPC实现 day01 我们实现了简单的服务端和客户端。我们简单总结一…

Pencils Protocol Season 2 收官在即,展望Season 3 及其权益

此前 Scroll 生态 LaunchPad &聚合收益平台 Pencils Protocol&#xff08;原 Penpad&#xff09;&#xff0c;推出了首个资产即其生态代币 PDD 的 Launch&#xff0c;Season 2 活动主要是用户通过质押 ETH 代币、组件战队等方式&#xff0c;来获得 Point 奖励&#xff0c;并…

mysql的explain

explain可以用于select&#xff0c;delete&#xff0c;insert&#xff0c;update的statement。 当explain用于statement时&#xff0c;mysql将会给出其优化器&#xff08;optimizer&#xff09;的执行计划。 通过explain字段生成执行计划表。下面来解析这个执行计划表的每一列…

正则表达式和sed

一、正则表达式 主要用来匹配字符串&#xff08;命令结果&#xff0c;文本内容&#xff09;&#xff0c; 通配符匹配文件&#xff08;而且是已存在的文件&#xff09; 基本正则表达式 扩展正则表达式 1.元字符 . 匹配任意单个字符&#xff0c;可以是一个汉字 […

【企业宣传片】拍摄思维提升,专业影视质感核心揭密,一课搞定

课程下载&#xff1a;【企业宣传片】拍摄-课程网盘链接提取码下载.txt资源-CSDN文库 更多资源下载&#xff1a;关注我。 课程介绍 大量案例分析宣传片拍摄的痛点要点 根据案例告诉你解决方案&#xff0c;讲透概念 改变你对企业宣传片的思维层级与认知 归纳总结对比不同案…

基于SSM的婚恋网站的设计与实现(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的婚恋网站的设计与实现&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spri…

MS41908M替代AN41908

产品简述 MS41908M 是一款用于网络摄像机和监控摄像机的镜头 驱动芯片他可完全替代AN41908。 芯片内置光圈控制功能&#xff1b;通过电压驱动方式以及扭矩纹 波修正技术&#xff0c;实现了噪声微步驱动。 主要特点 电压驱动方式&#xff0c;256 微步驱动电路&#xff08;两通道…

多区域OSPF路由配置

一、基础配置 1.搭建实验拓扑图 2.实验编址 具体如何配置可以看这一篇详细的博文&#xff1a;单区域OSPF实验-CSDN博客 3.分别检查六个路由器的配置&#xff1a; 使用命令display ip interface brief R1的配置 其他大家可以调出来&#xff0c;再与实验拓扑图进行比对&#…

机器人非线性系统反馈线性化与解耦

机器人非线性系统的反馈线性化和解耦是控制理论中的两个重要概念&#xff0c;它们分别用于简化系统分析和设计过程&#xff0c;提高控制系统的性能。 首先&#xff0c;反馈线性化是一种将非线性系统转化为线性系统的技术。在机器人控制中&#xff0c;由于机器人本身是一个强耦…

那些年我与c++的叫板(一)--string类自实现

引子&#xff1a;我们学习了c中的string类&#xff0c;那我们能不能像以前数据结构一样自己实现string类呢&#xff1f;以下是cplusplus下的string类&#xff0c;我们参考参考&#xff01; 废话不多说&#xff0c;直接代码实现&#xff1a;&#xff08;注意函数之间的复用&…

【C语言】5.C语言函数(2)

文章目录 7.嵌套调⽤和链式访问7.1 嵌套调⽤7.2 链式访问 8.函数的声明和定义8.1 单个⽂件8.2 多个⽂件8.3 static 和 extern8.3.1 static 修饰局部变量8.3.2 static 修饰全局变量8.3.3 static 修饰函数 7.嵌套调⽤和链式访问 7.1 嵌套调⽤ 嵌套调用就是函数之间的互相调用。…

1、sql server数据库进行sql注入

靶机取自&#xff1a;墨者sql server 1、判断数据库类型 抓包知sql server&#xff0c;所以注入语句跟MySQL有些区别 2、判断注入点 “http://219.153.49.228:42514/new_list.asp?id2 ”&#xff0c;当id2 and 11时显示正确&#xff0c;id2 and 12时页面报错。 3、确定列…

BERT for Joint Intent Classification and Slot Filling 论文阅读

BERT for Joint Intent Classification and Slot Filling 论文阅读 Abstract1 Introduction2 Related work3 Proposed Approach3.1 BERT3.2 Joint Intent Classification and Slot Filling3.3 Conditional Random Field 4 Experiments and Analysis4.1 Data4.2 Training Detail…

【董晓算法】动态规划之背包DP问题(2024.5.11)

前言&#xff1a; 本系列是学习了董晓老师所讲的知识点做的笔记 董晓算法的个人空间-董晓算法个人主页-哔哩哔哩视频 (bilibili.com) 动态规划系列 【董晓算法】动态规划之线性DP问题-CSDN博客 01背包 步骤&#xff1a; 分析容量j与w[i]的关系&#xff0c;然后分析是否…