当前位置: 首页 > news >正文

C#自学笔记:委托与事件

委托

委托代表对一个或多个方法的引用,类似于函数指针,可以将方法作为参数传递给其他方法。

委托是函数(方法)的容器,用来存储、传递函数(方法)

本质

委托的本质是一个类,用来定义函数(方法)的类型(返回值和参数的类型)

不同的函数(方法)必须对应和各自“格式”一致的委托

基本语法

关键字:delegate

语法:访问修饰符 delegate 返回值 委托名(参数列表);

写在哪里?

• 可以声明在namespace和class语句块中,但是更多的写在namespace中

简单记忆委托语法就是函数声明语法前面加一个delegate关键字

使用

委托常用在:
  1. 作为类的成员
  2. 作为函数的参数
    • 访问修饰符默认不写,为public,在别的命名空间中也能使用
    • 如果设置成private,其他的命名空间就不能用了
基本使用
//声明了一个可以用来存储无参无返回值函数的容器
//这里只是定义了规则,并没有使用
delegate void MyFunCallback();
//委托规则的声明是不能重名的(同一语句快中),也就是说不能重载
//表示用来装载或传递,返回值为int,有一个int参数的函数的委托容器规则
public delegate int MyFun2Callback(int a);class Program
{static void Main(string[] args){Cosole.WriteLine("委托");//无返回值无参数//方式一MyFunCallback f1 = new MyFunCallback(Fun);//调用委托,会调用里面的所有函数f1.Invoke();//方式二//直接写函数名,不能加括号MyFunCallback f12 = Fun;f12();//有返回值有参数//方式一MyFun2Callback f2 = new MyFun2Callback(Fun2);Console.WriteLine(f2.Invoke(2));//方式二MyFun2Callback f22 = Fun2;Console.WriteLine(f3(1));}static void Fun(){Console.WriteLine("123123");}static int Fun2(int value){return value;}
}
一般使用
class Text
{public MyFunCallback fun;public MyFun2Callback fun2;public void TestFun(MyFunCallback fun, MyFun2Callback fun2){//先处理一些别的游戏逻辑,当这些逻辑处理完了之后再执行传入的函数int i = 1;i *= 2;i += 2;//可以直接执行fun();fun2(i);//也可以先存起来,以后再执行this.fun = fun;this.fun2 = fun2;}//增public void AddFun(MyFunCallback fun, MyFun2Callback fun2){this.fun += fun;this.fun2 += fun2;}//删//要是为空的话也能减,就是说如果没有这个函数也能减,不会报错public void RemoveFun(MyFunCallback fun, MyFun2Callback fun2){this.fun -= fun;this.fun2 -= fun2;}
}

多播委托

委托变量可以存储多个函数

按顺序依次执行添加的函数

//如何用委托存储多个函数
MyFunCallback ff = Fun;
ff += Fun;
ff();MyFunCallback ff = null;
ff + Fun;
ff += Fun;
ff();
//从容器中移除指定的函数
ff -= Fun;
//多减不会报错,无非就是不处理而已
ff -= Fun;
ff();
//清空容器
ff = null;ff();	//为空时运行会报错
//规范写法
if (ff != null)
{ff();
}
//简写
ff?.Invoke();Test t = new Test();
t.AddFun(Fun, Fun2);
t.fun();
t.fun2(50);

注意,如果存储了多次同一个函数,会多次调用同一个函数

泛型委托

委托是支持泛型的,可以让返回值和参数可变,更方便我们使用
delegate T MyFun3Callback<T, K>(T v, K k);

系统定义好的委托

一般情况下我们不会自己去声明委托,都是使用系统定义好的
  1. Action
using System//Action其实就是系统定义好的一个无参无返回值的委托
Action action = Fun;
action += Fun;
action();

Action底层

namespace System
{...public delegate void Action();
}
  1. Func<>

是一个泛型委托

//可以指定返回值类型的泛型委托
Func<string> funcString = Fun4;
Func<int> funcInt = Fun5;static string Fun4()
{return "";
}static int Fun5()
{return 1;
}

Func底层

namespace System
{...public delegate TResult Func<out TResult>();
}
  1. Action<>

可以传n个参数的委托,最多传16个参数,这种不算重载,泛型不同代表着命名不同,说明有16个不同的委托

//有参无返回值
Action<int, string> action2 = Fun6;static void Fun6(int i, string s)
{
}

Action<>底层

namespace System
{...public delegate void Action<in T>(T obj);
}
  1. Func<>

可以传n个参数的并且有返回值的,系统也提供了16个委托

注意⚠️:参数比Action多一个,因为有一个参数是返回值,放在最后一个位置,所以一共有17个委托,要是没有参数的话,就只有一个返回值作为参数

Func<int, int> func = Fun2;static int Fun2(int i)
{return i;
}

Func<>底层

namespace System
{...public delegate TResult Func<in T, out TResult>(T arg);
}

事件

事件是基于委托的存在

事件是委托的安全包裹,让委托的使用更具有安全性

事件是一种特殊的变量类型

使用

语法:访问修饰符 event 委托类型 事件名;

  1. 事件在类中作为成员变量
  2. 使用方式和委托一模一样

事件和委托的区别:

  1. 不能在类外部赋值
  2. 不能在类外部调用
  3. 事件只能在外部通过+-=来添加和移除函数

注意:它只能作为成员变量而存在,于类和接口以及结构体中,不能在函数中作为临时变量来使用

class Test
{//委托成员变量 用于存储 函数的public Action myFunCallback;//事件成员变量 用于存储 函数的public event Action myEvent;public Test(){//事件的使用和委托一模一样,只是有些细微的区别myFunCallback = TestFun;myFunCallback += TestFun;myFunCallback -= TestFun;myFunCallback();myFunCallback.Invoke();myFunCallback = null;myEvent = TestFun;myEvent += TestFun;myEvent -= TestFun;myEvent();myEvent.Invoke();myEvent = null;}public void TestFun(){}public void DoEvent(){myEvent?.Invoke();}
}class Program
{static void Main(string[] args){Console.WriteLine("事件");Test t = new Test();//委托可以在外部赋值t.myFunCallback = null;t.myFunCallback = ProgramFun;//事件不能在外部赋值,会报错t.myEvent = null;t.myEvent = ProgramFun;//虽然不能直接赋值,但是可以通过加减去添加或移除函数t.myEvent += ProgramFun;t.myEvent -= ProgramFun;//⚠️但是这样写是错误的,因为事件里只重载了+=这种运算符t.myEvent = t.myEvent + ProgramFun;//委托是可以在外部调用的t.myFunCallback();t.myFunCallback.Invoke();//事件不能在外部调用,会报错t.myEvent();t.myEvent.Invoke();//只能在类的内部封装和调用t.DoEvent();}static void ProgramFun(){}
}

使用事件的原因

  1. 防止外部随意修改置空委托
  2. 防止外部随意调用委托
  3. 事件相当于对委托进行了一次封装,让其更加安全

事件和委托的区别

事件就是特殊的委托
  1. 事件不能在外部使用赋值符号=,只能使用+-=运算符,而委托能用
  2. 事件不能在外部执行,委托可以
  3. 事件不能作为函数中的临时变量,委托可以。
http://www.vanclimg.com/news/1455.html

相关文章:

  • 电流探头去磁与调零操作对测量精度的影响
  • 企业HR如何将AI Agent作为战略引擎重构业务流程
  • 7月29日总结
  • thradlocal
  • ThreadLocal线程隔离值为NULL,直接复制使用封装类
  • 基于 Nacos + Higress 的 MCP 开发新范式,手把手教程来了!
  • 使用Vue.js实现动态表单字段
  • 特征 - kkksc03
  • 7月29日
  • 图神经网络的未来与挑战
  • 网站SSL证书怎么选?不用SSL证书会怎么样?
  • 安全可靠的PolarDB V2.0 (兼容MySQL)产品能力及应用场景 - 王权富贵
  • 2025牛客暑期多校训练营5_J
  • 【LeetCode 24】力扣算法:两两交换链表中的节点
  • Pwn2Own柏林2025:第三天赛事成果与技术漏洞全记录
  • POLIR-Laws-民事诉讼法:手机录音能否作为民事诉讼证据?怎么录音才能被法院采信?
  • MCP是如何工作的?
  • OBS
  • 屏幕翻译 安卓app
  • 微算法科技(NASDAQ:MLGO)应用区块链联邦学习(BlockFL)架构,实现数据的安全传输
  • 星球助手发布更新 v1.7.0
  • 使用Spring Cloud和Resilience4j实现微服务容错与降级 - spiderMan1
  • WinForm自定义控件实现类似百度网盘客户端菜单组件
  • 【比赛记录】2025CSP-S模拟赛29
  • 树形dp练习
  • python中 命令行参数解析模块 argparse
  • 基于YOLOv8的狗狗品种(多达60种常见犬类)品种鉴别识别项目|完整源码数据集+PyQt5界面+完整训练流程+开箱即用!
  • 公钥和私钥的部分作用
  • 使用 Kiro AI IDE 3小时实现全栈应用Admin系统
  • soildworks建模界面添加图片