SevenDouble

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

学习笔记:C#高级进阶语法——委托(Delegate)

四、委托

4.1、什么是委托,委托的本质是什么呢?

​ 1、形似一个方法,用delegate修饰符修饰。

所谓委托,ILSpy反编译识别底层----生成一个一个的类。如果定义在class外部:独立生成一个类,如果定义在class内部,生成了一个类中类:包含一个

2、所以委托的本质:就是一个类。

4.2、委托的实例化,执行委托

1、实例化一个委托,必须传入一个和当前委托的参数和返回值完全吻合的方法

2、如果执行委托-----执行Invoke方法,就会把指向这个委托的方法给执行掉;

形态上理解下委托:委托---->类,用invoke执行方法(方法可以把一段业务逻辑丢给委托,也就是lamdaba表达式--->匿名函数)

namespace D_MyDelegate
{
/// <summary>
/// 无返回值无参数的类外部委托
/// </summary>
public delegate void NoReturnNoParaOutClass();
public class CustomDelegate
{
#region 定义委托
/// <summary>
/// 无参数无返回值委托
/// </summary>
public delegate void NoReturnNoPara();
/// <summary>
/// 无返回值有参数委托
/// </summary>
/// <param name="x"></param>
public delegate void NoReturnWithPara(int x, int y);
/// <summary>
/// 有返回值有参数委托
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
public delegate int WithReturnWithPara(int x);
/// <summary>
/// 有返回值无参数委托
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public delegate int WithReturnNoPara(out int x, ref int y);
#endregion
/// <summary>
/// 实例化委托
/// </summary>
public void Show()
{
{
//实例化委托
NoReturnNoPara method = new NoReturnNoPara(NoReturnNoParaMethod);
method.Invoke();
var res = method.BeginInvoke(null, null);//在.NET Framework有效,启动一个线程来执行这个委托指向的方法。
//在.NET Core中不再支持
method.EndInvoke(res);//回调--现在都不支持了
}
{
NoReturnWithPara method = new NoReturnWithPara(NoReturnWithParaMethod);
method.Invoke(1, 0);
}
{
WithReturnWithPara method = new WithReturnWithPara(WithReturnWithParaMethod);
int a = method.Invoke(1);
Console.WriteLine(a);
}
{
WithReturnNoPara method = new WithReturnNoPara(WithReturnNoParaMethod);
int x;
int y = 2;
int a;
a = method.Invoke(out x, ref y);
}
}
public void NoReturnNoParaMethod()
{
Console.WriteLine("this is NoReturnNoPara");
}
public void NoReturnWithParaMethod(int x, int z)
{
Console.WriteLine("this is NoReturnWithPara");
}
public int WithReturnWithParaMethod(int x)
{
Console.WriteLine("this is WithReturnWithParaMethod");
return x;
}
public int WithReturnNoParaMethod(out int x, ref int y)
{
return x = y = 0;
}
}
}

4.3、委托的作用和意义(可以怎么用?使用场景?)

{
Student student = new() { ID = 1, Name = "凭栏听雨", Age = 28 };
student.SayHi();
//打招呼在不同的地方有不同的打招呼方式
//1、我需要增加 3个地方人的打招呼方式,怎么实现?
//BeiJing "你好,喝豆汁儿去?"
//GuangDong "靓仔,嗦粉哟?"
//ShanXi "弄撒恰?"
//方案一:每个地区增加一个方法:
student.SayHiShanXi();
student.SayHiGuangDong();
student.SayHiBeiJing();
//方案二:用一个方法将地区传参进去
student.SayHiByPara(UserType.BeiJing);
student.SayHiByPara(UserType.ShanXi);
student.SayHiByPara(UserType.GuangDong);
//问题一:如果我要增加一个公共方法,打招呼的时候招招手
//方案一需要在每个方法都增加,有重复代码
//方案二在方法中增加一句,方案二更好
//问题二:如果我要增加一个上海人,ShanHai "侬好"
//方案一增加一个方法,不需要改动原来的方法,耦合性低,方案一更好
//方案二需要改动原有方法
//有没有一种方案能兼顾两种?委托
DoHandleDelegate doHandleBeiJing = new DoHandleDelegate(student.SayHiBeiJing);
student.SayHiPrefect(doHandleBeiJing);
DoHandleDelegate doHandleShanXi = new DoHandleDelegate(student.SayHiShanXi );
student.SayHiPrefect(doHandleShanXi);
DoHandleDelegate doHandleGuangDong = new DoHandleDelegate(student.SayHiGuangDong);
student.SayHiPrefect(doHandleGuangDong);
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace D_MyDelegate
{
public class Student
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public void SayHi()
{
Console.WriteLine("你好");
}
//BeiJing "你好,喝豆汁儿去?"
//GuangDong "靓仔,嗦粉哟?"
//ShanXi "弄撒恰?"
public void SayHiBeiJing()
{
Console.WriteLine("你好,喝豆汁儿去?");
}
public void SayHiGuangDong()
{
Console.WriteLine("靓仔,嗦粉哟?");
}
public void SayHiShanXi()
{
Console.WriteLine("弄撒恰?");
}
public void SayHiByPara(UserType userType) {
switch (userType)
{
case UserType.BeiJing:
Console.WriteLine("你好,喝豆汁儿去?");
break;
case UserType.GuangDong:
Console.WriteLine("靓仔,嗦粉哟?");
break;
case UserType.ShanXi:
Console.WriteLine("弄撒恰?");
break;
default:
break;
}
}
public delegate void DoHandleDelegate();
public void SayHiPrefect(DoHandleDelegate doHandle) {
doHandle.Invoke();
Console.WriteLine("一起勾肩搭背吃早饭!");
}
}
public enum UserType {
BeiJing = 1,
GuangDong = 2,
ShanXi = 3
}
}

4.4、微软内置委托 Action、Func

//微软提供的两个委托
{
//可有可无参数的委托,但是没有返回值 最多有16个泛型参数
//如果想要17或者更多的,可以把Action的定义拿出来,扩展定义一下
Action<int> action = new Action<int>(i => { });
Action<int, string> action1 = new Action<int, string>((i, s) => { });
Action<int, string, DateTime, double, float, object, decimal, StringBuilder,
int, string, DateTime, double, float, object, decimal, StringBuilder> action2 = null;
//可有可无参数,有返回值 最多有16个泛型参数 最多有17个泛型参数 最后一个参数为返回值的类型
//有一个返回值,无参数
Func<int> func = new Func<int>(() => { return 10; });
//一个参数一个返回值
Func<int, string> func1 = new Func<int, string>(i => { return ""; });
Func<int, string, DateTime, double, float, object, decimal, StringBuilder,
int, string, DateTime, double, float, object, decimal, StringBuilder, int> func2 = null;
//返回元祖
Func<(int, string)> func3 = new Func<(int, string)>(() => { return (10, "你好"); });
}

4.5、委托的嵌套使用,Asp.net Core中间件的核心设计,委托的多重嵌套

namespace D_MyDelegate
{
public class DelegateExtension
{
//诉求
//1、InvokeAction类型,方法Show
//2、执行ExeMethod前面或者后面,希望增加一些业务逻辑,但是不希望修改ExeMethod方法
public static void Show()
{
InvokeAction invokeAction = new InvokeAction();
invokeAction.ExeMethod();
//将原方法包装到一个委托中
Action action = new Action(invokeAction.ExeMethod);
//Console.WriteLine("Exec ExeMethod Before");
//action.Invoke();
//Console.WriteLine("Exec ExeMethod After");
//再去执行这个委托 其实就是将上面这三句话封装到方法中了
Action<Action> action2 = new Action<Action>(ExecNextMethod);
action.Invoke();
}
public static void ExecNextMethod(Action action)
{
Console.WriteLine("Exec ExeMethod Before");
action.Invoke();
Console.WriteLine("Exec ExeMethod After");
}
}
public class InvokeAction
{
public void ExeMethod()
{
//Console.WriteLine("Exec ExeMethod Before");
Console.WriteLine("Exec ExeMethod");
//Console.WriteLine("Exec ExeMethod After");
}
}
}
//可以无限增加业务逻辑的扩展
namespace D_MyDelegate
{
public class DelegateExtension
{
//诉求
//1、InvokeAction类型,方法Show
//2、执行ExeMethod前面或者后面,希望增加一些业务逻辑,但是不希望修改ExeMethod方法
//3、我们希望无限制的嵌套业务逻辑
public static void Show()
{
InvokeAction invokeAction = new InvokeAction();
//invokeAction.ExeMethod();
//将原方法包装到一个委托中
Action action = new Action(invokeAction.ExeMethod);
//Console.WriteLine("Exec ExeMethod Before");
//action.Invoke();
//Console.WriteLine("Exec ExeMethod After");
//再去执行这个委托 其实就是将上面这三句话封装到方法中了
Action<Action> action2 = new Action<Action>(ExecNextMethod);
//action.Invoke();
Func<Action, Action> func2 = new Func<Action, Action>(ExecNextMethod001);
action = func2.Invoke(action);
Func<Action, Action> func3 = new Func<Action, Action>(ExecNextMethod002);
action = func3.Invoke(action);
Func<Action, Action> func4 = new Func<Action, Action>(ExecNextMethod003);
action = func4.Invoke(action);
action.Invoke();
}
public static void ExecNextMethod(Action action)
{
Console.WriteLine("Exec ExeMethod Before");
action.Invoke();
Console.WriteLine("Exec ExeMethod After");
}
public static Action ExecNextMethod001(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExecNextMethod001 Before");
action.Invoke();
Console.WriteLine("Exec ExecNextMethod001 After");
});
}
public static Action ExecNextMethod002(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExecNextMethod002 Before");
action.Invoke();
Console.WriteLine("Exec ExecNextMethod002 After");
});
}
public static Action ExecNextMethod003(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExecNextMethod003 Before");
action.Invoke();
Console.WriteLine("Exec ExecNextMethod003 After");
});
}
}
public class InvokeAction
{
public void ExeMethod()
{
//Console.WriteLine("Exec ExeMethod Before");
Console.WriteLine("Exec ExeMethod");
//Console.WriteLine("Exec ExeMethod After");
}
}
}

​ 通过循环的方式,一次性获取所有的特性,将要核心方法前后增加的内容,封装成为一个特性,标记在核心方法上。就可以实现无限制扩展,而不需要改动任何代码。

namespace D_MyDelegate
{
public class DelegateExtension
{
public void Show()
{
InvokeAction invokeAction = new InvokeAction();
Action action = () => { invokeAction.ExeMethod(); };
Type type = invokeAction.GetType();
if (type.IsDefined(typeof(ActionBefor), true))
{
foreach (BaseAttribute attribute in type.GetCustomAttributes(typeof(BaseAttribute), true))
{
action = attribute.Do(action);
}
}
action.Invoke();
}
}
public class InvokeAction
{
[ActionBefor]
[ActionAfter]
public void ExeMethod()
{
//Console.WriteLine("Exec ExeMethod Before");
Console.WriteLine("Exec ExeMethod,这里是原始的方法,原始逻辑");
//Console.WriteLine("Exec ExeMethod After");
}
}
public abstract class BaseAttribute : Attribute
{
public abstract Action Do(Action action);
}
public class ActionBefor : BaseAttribute
{
public override Action Do(Action action)
{
return new Action(() =>
{
{
Console.WriteLine("我在这里扩充了一些自己的东西。。。");
}
action.Invoke();
});
}
}
public class ActionAfter : BaseAttribute
{
public override Action Do(Action action)
{
return new Action(() =>
{
{
Console.WriteLine("我在这里扩充了一些自己的东西000011。。。");
}
action.Invoke();
});
}
}
}

4.6、多播委托

namespace D_MyDelegate
{
public class CustomMulticastDelegation
{
public void Show()
{
Action action = new Action(DoNothing);
//委托还可以通过+=把更多的方法包装到委托中
//action += DoNothing;
//action += DoNothing;
//action.Invoke();
//+=的操作,可以操作哪些方法呢?
action += DoNothing;//普通方法
action += DoNothingStatic;//静态方法
action += new Student().SayHi;//实例方法
action += () => { Console.WriteLine("这是lambda"); };//lambda表达式
//-=的操作,按顺序减去方法
action -= DoNothing;//普通方法
action -= DoNothingStatic;//静态方法
action -= new Student().SayHi;//实例方法
action -= () => { Console.WriteLine("这是lambda"); };//lambda表达式
//-=的操作,对于匿名的东西没有作用,按照名称去减的,否则找到的不是同一个
//所以这边还是会执行最后两个方法
action.Invoke();
}
private void DoNothing()
{
Console.WriteLine("什么也没做");
}
private static void DoNothingStatic()
{
Console.WriteLine("什么也没做");
}
}
}

4.7 委托实现观察者模式

using System;
namespace MyDelegate.Event
{
public class Dog : IObject
{
//public Dog(int id, string i)
//{
//}
public void DoAction()
{
this.Wang();
}
public void Wang()
{
Console.WriteLine("{0} Wang", this.GetType().Name);
}
}
}
using System;
namespace MyDelegate.Event
{
/// <summary>
/// 订户
/// </summary>
public class Mother : IObject
{
public void DoAction()
{
this.Wispher();
}
public void Wispher()
{
Console.WriteLine("{0} Wispher", this.GetType().Name);
}
}
}
using System;
namespace MyDelegate.Event
{
public class Mouse : IObject
{
public void DoAction()
{
this.Run();
}
public void Run()
{
Console.WriteLine("{0} Run", this.GetType().Name);
}
}
}
namespace MyDelegate.Event
{
public interface IObject
{
void DoAction();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyDelegate.Event
{
/// <summary>
/// 猫:
///
/// 面试者:以面向对象的思想实现一下的场景:
/// 猫:Miao一声,紧接着引发了一系列的行为~
/// Miao:引发了一系列的动作;
///
/// 从代码层面来说:代码这样写好吗?
/// 1. 猫职责不单一(猫就是猫,他的行为只有Miao一声)
/// 2. 依赖太重,依赖了很多的普通类; 被依赖的类如果修改,可能会引发这个猫也要修改;---代码不稳定;
/// 3. 如果要控制顺序---也要修改代码; 有新需求,必须要修改历史代码---开闭原则;
///
/// 如何解决呢? 第一个问题:让猫的职责单一, 后续触发的行为,猫Miao一声之后,只负责触发; 触发的是一堆的行为;
/// 请问:如果要希望在触发一个行为后,能够执行多个行为,执行一系列的行为?? 怎么办?-------多播委托;
///
/// 核心:把依赖的东西转移到上端,保证当前类的稳定; ----可以做到解耦
/// 二者实现本质:是相通的; 都是类似于一个盒子, OOP: 盒子中装对象 委托:盒子装方法;
///
///
/// </summary>
public class Cat
{
/// <summary>
/// 通过OOP 继承来实现的Observer
/// </summary>
public List<IObject> ObserList=new List<IObject>();
public void MiaoObserver()
{
Console.WriteLine($"{this.GetType().Name} MiaoObserver========");
//也要触发一串行为
foreach ( IObject item in ObserList )
{
item.DoAction();
}
}
//通过委托 来实现的Observer
public Action ActionHander; //委托的本质:类
public void Miao()
{
Console.WriteLine($"{this.GetType().Name} Miao========");
ActionHander.Invoke();
}
//前面是一个类
//下面是一个类的实例
//事件
public event Action ActionHanderEvent;
public void MiaoEvent()
{
Console.WriteLine($"{this.GetType().Name} MiaoEvent========");
ActionHanderEvent.Invoke(); //这个行为要一定是执行 MiaoEvent方法的时候才触发的;
}
//什么是事件,其实就是委托的实例+关键字; 事件是一个特殊的委托;
//委托和事件有什么区别?
//1 多个了关键字
//2 事件的权限控制会更加严格--事件的执行,只能,必须在声明这个事件所在的类的内部才能执行;
//已经有了委托,为什么还要事件呢?----在系统框架设计中,需要这样的权限控制;
}
public class ChildCat : Cat
{
public void Show()
{
//base.ActionHanderEvent += () => { };
//base.ActionHanderEvent -= () => { };
//base.ActionHanderEvent.Invoke(); //也是不允许的;
}
}
}

posted on   七之缘  阅读(100)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示