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();}
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASP.NET在线二手交易系统的设计与实现

摘 要 随着当今社会信息技术的进步&#xff0c;基于互联网的各种应用日益受到了人们的重视&#xff0c;二手商品的重新利用也逐渐被人们关注&#xff0c;二手交易系统就在这种形势下产生了&#xff0c;它利用网络&#xff0c;改变了人们的购物方式。 本文是基于现代二手交易…

Kotlin扩展函数和运算符重载

扩展函数 fun String.lettersCount():Int{var count 0for(i in this){if(i.isLetter())count}return count } fun main(){val str:String "12we"println(str.lettersCount()) } 相当于直接将方法写在类里面。函数体内可以直接使用this而不用传参。 运算符重载 …

基于Python的jieba库分析《斗破苍穹》文本中的高频词汇

分析《斗破苍穹》文本中的高频词汇 在进行文本分析时&#xff0c;了解文本中出现频率较高的词汇对于把握文本的主题和风格非常有帮助。本文将介绍如何使用Python的jieba库对《斗破苍穹》这部小说的文本进行分词处理&#xff0c;并统计高频词汇的出现次数&#xff08;本文只统计…

AI作画算法详解:原理、应用与未来发展

随着人工智能技术的不断发展&#xff0c;AI作画逐渐成为了一个热门话题。AI作画&#xff0c;即利用人工智能算法生成绘画作品&#xff0c;不仅仅是技术的展示&#xff0c;更是艺术与科技结合的创新体现。本文将深入探讨AI作画的核心算法原理&#xff0c;并通过实例帮助读者更好…

自然语言处理通用框架BERT原理解读

相关代码见文末 1.概述 问题背景: 传统Seq2Seq模型的局限性: 早期的机器翻译和文本生成任务常采用基于循环神经网络(RNN)的序列到序列(Seq2Seq)模型,这类模型在处理长序列时容易遇到梯度消失/爆炸问题,导致训练效率低,难以捕捉长期依赖。 RNN网络的问题: RNN及其变…

哈希表的理解和实现

目录 1. 哈希的概念 (是什么) 2. 实现哈希的两种方式 (哈希函数) 2.1. 直接定址法 2.2. 除留余数法 2.2.1. 哈希冲突 3. 补充知识 3.1. 负载因子 3.2. 线性探测和二次探测 4. 闭散列实现哈希表 (开放定址法) 4.1. 开放定址法的实现框架 4.2. Xq::hash_table::insert…

mysql 查询---多表设计

部分数据 1distinct去重 select distinct job from tb_emp;select * from tb_emp where id in (1,2,3); select * from tb_emp where id between 1 and 5; select * from tb_emp where name like __; #下划线匹配单个字符, %匹配任意多个字符select min(entrydate) from tb_e…

C++ 日志库 log4cpp 编译、压测及其范例代码 [全流程手工实践]

文章目录 一、 log4cpp官网二、下载三、编译1.目录结构如下2.configure 编译3.cmake 编译 四、测试五、压测源码及结果1.运行环境信息2.压测源码3.压测结果 文章内容&#xff1a;包含了对其linux上的完整使用流程&#xff0c;下载、编译、安装、测试用例尝试、以及一份自己写好…

机器学习入门介绍

各位大佬好 &#xff0c;这里是阿川的博客 &#xff0c; 祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 目录 三大方向机器学习产生的原因机器如何学习…

springboot整合rabbitmq的不同工作模式理解

前提是已经安装并启动了rabbitmq&#xff0c;并且项目已经引入rabbitmq&#xff0c;完成了配置。 不同模式所需参数不同&#xff0c;生产者可以根据参数不同使用重载的convertAndSend方法。而消费者均是直接监听某个队列。 不同的交换机是实现不同工作模式的关键组件.每种交换…

SQL注入漏洞常用绕过方法

SQL注入漏洞 漏洞描述 Web 程序代码中对于用户提交的参数未做过滤就直接放到 SQL 语句中执行&#xff0c;导致参数中的特殊字符打破了原有的SQL 语句逻辑&#xff0c;黑客可以利用该漏洞执行任意 SQL 语句&#xff0c;如查询数据、下载数据、写入webshell 、执行系统命令以及…

C语言学习【printf函数和scanf函数】

C语言学习【printf函数和scanf函数】 printf()函数和scanf()函数可以让用户与程序交流&#xff0c;是输入/输出函数 printf()函数 请求printf()函数打印数据的指令要与待打印数据的类型相匹配。例如&#xff0c;打印整数时使用%d&#xff0c;打印字符时使用%c。这些符号被称…