委托
委托一、什么是委托,委托的本质是什么?
[*]跟方法有点类似,有参数,返回值,访问修饰符+delegate --委托--特别的方法?
[*]委托的本质是什么?是方法吗?
[*]反编译试试:发现界说的委托-----再CustomDelegate ----有对应的class
https://img2023.cnblogs.com/blog/1462645/202312/1462645-20231221155859657-1326549323.png
[*]委托的本质是什么?---Class(类),继承自一个MulticastDelegate的特别类,自己在界说类的时候,是无法继承的。包含的有构造函数和方法。
[*]委托既然是一个类---怎么使用这个类?new ---调用方法/属性
public class DelegateDemo
{
public delegate void NoReturnWithoutParaout();
public delegate void NoReturnWithParaout(out int x);
public delegate void NoReturnWithParaRef(ref int x);
public delegate int WithReturnWithoutPara();
public delegate int WithReturnWithPara(int x, int y);
public static voidNoReturnWithoutParaoutfunc()
{
Console.WriteLine("NoReturnWithoutParaoutfunc called!");
}
public static void NoReturnWithParaoutfunc(out int x)
{
x = 100;
Console.WriteLine("NoReturnWithParaoutfunc called!");
}
public static void NoReturnWithParaReffunc(ref int x)
{
x = 100;
Console.WriteLine("NoReturnWithParaReffunc called!");
}
public static int WithReturnWithoutParafunc()
{
Console.WriteLine("WithReturnWithoutParafunc called!");
return 100;
}
public static int WithReturnWithParafunc(int x, int y)
{
Console.WriteLine("WithReturnWithParafunc called!");
return x + y;
}
}二、委托的实例化
[*]ILSpy反编译--委托的本质实在是一个类
[*]委托本质是一个类,这个类的构造参数--Method方法
[*]委托可以通过New来实例化,要求传递一个和这个委托的参数和返回值完全匹配的方法,委托有什么参数(几个,什么范例)---完全匹配
[*]委托的实例---可以直接指向和这个委托参数+返回值完全匹配的方法;--语法糖--编译器给我们提供便捷功能new省略掉了。
[*]执行委托实例的Invoke方法--去执行这个委托实例化的指向的这个方法---执行方法;
[*]就可以执行这个实例内部的三个方法
[*]多种实例化:new、指向一个方法、指向一个lambda表达式
NoReturnWithoutParaout noReturnWithoutParaout = new NoReturnWithoutParaout(NoReturnWithoutParaoutfunc);
noReturnWithoutParaout();三、委托的作用和意义
现在有一个弟子类
{
public int Id { get; set; }
public string Name { get; set; }
public int ClassId { get; set; }
public int Age { get; set; }
public Student() { }
public void SayHi()
{
Console.WriteLine("大家好,我是学员,我叫{0}", this.Name);
}
public void Study()
{
Console.WriteLine("学习.net高级班公开课");
}
public static void StudyAdvanced()
{
Console.WriteLine("学习.net高级班vip课");
}
}我们可以调用一下弟子中的方法
{
Student stu = new Student()
{
Id = 1,
Name = "张三",
ClassId = 1,
Age = 18
};
stu.SayHi();
}我们现在多了一个这样的使用场景的问题
场景1. 弟子分类?武汉人、上海人、广东人--三种不同范例的人;问候的口语不一样;
界说三种人:a.武汉 b.上海 c.广东人
问好的方式有多种;
WuHan 人: 吃了么?
GuanDong 人:靓仔/靓女~ 雷猴!
BeiJing 人: 你好!
问题一:如果想要增加一个地方的人;
解决方案一:(多增加几个方法)可以为每一个地方的人,各自界说一个方法
public void SayShangHai()
{
Console.WriteLine("招招手~");
Console.WriteLine("侬好?");
}
public void SayHiWuHan()
{
Console.WriteLine("招招手~");
Console.WriteLine("吃了么?");
}
public void SayHiGuanDong()
{
Console.WriteLine("招招手~");
Console.WriteLine("靓仔/靓女~ 雷猴!");
}
public void SayHiBeiJing()
{
Console.WriteLine("招招手~");
Console.WriteLine("你好!");
}解决方案二:(传递参数来判断)
/// 传入参数,分辨类型----使用枚举--避免调用方出错;
/// 不同的类型给不同的逻辑
public enum UserType
{
Wuhan = 1,
GuangDong = 2,
BeiJing = 3
}
public void SayHi(UserType userType) //1. 哪儿的人2 哪儿的人
{
Console.WriteLine("招招手~");//只需要一句代码搞定了
switch (userType)
{
case UserType.Wuhan:
Console.WriteLine("吃了么?");
break;
case UserType.BeiJing:
Console.WriteLine("你好!");
break;
case UserType.GuangDong:
Console.WriteLine("靓仔/靓女~ 雷猴!");
break;
default:
throw new Exception("No userType");
}
}点评:
方案一:更好---每个方案,可以相互独立,互不干扰,逻辑没有解耦;满足单一职责;
方案二:耦合在一起,如果有需求的升级,大概需要修改原有的方案,代码大概会不稳固
问题二:如果我想要增加一些公共的业务逻辑呢?问好前---伴随一个动作---“招招手”
再比力:方案二更有有上风了;只需要增加一句,就可以覆盖所有的人;
方案一出现了重复代码;
有没有一个完美方案呢?
自上而下比力:逻辑单一,逻辑解耦,职责单一,保证代码的稳固性;
如何写?
思路:传递参数枚举---分辨不同地方的人----给出不同的业务逻辑-----(传枚举usertype---选择逻辑)----直接传递逻辑呗; 逻辑在哪儿? 封装成一个方法; 实在就是需要传递一个方法;
问题:如何把方法当做参数来进行传递???啥??? 当然是委托;
public delegate void DoHandlerDelegate();
public void SayHiPerfect(DoHandlerDelegate doHandler)
{
Console.WriteLine("保持微笑~~");
doHandler.Invoke();
}在主步伐执行的时候
Console.WriteLine("通过委托传递逻辑 \r\n");
DoHandlerDelegate doHandlerWuhan = new DoHandlerDelegate(student.SayHiWuHan);
student.SayHiPerfect(doHandlerWuhan);
DoHandlerDelegate doHandlerBeiJin = new DoHandlerDelegate(student.SayHiBeiJing);
student.SayHiPerfect(doHandlerBeiJin);
DoHandlerDelegate doHandlerGuangDong = new DoHandlerDelegate(student.SayHiGuanDong);
student.SayHiPerfect(doHandlerGuangDong);问题一:增加一个上海人 --- 增加了一个方案; 方法单一; 方法相互独立,互不干扰;--稳固性,逻辑解耦
问题二:增加一个公共的业务逻辑,只需要在SayHiPerfect 增加一个动作即可;去掉重复代码;
public void SayShangHai()
{
Console.WriteLine("招招手~");
Console.WriteLine("侬好?");
}主步伐中
DoHandlerDelegate doHandlerShangHi = new DoHandlerDelegate(student.SayShangHai);
student.SayHiPerfect(doHandlerShangHi); 委托的价值:
1.逻辑解耦,代码的职责单一
2.去掉重复代码
建议: 如果代码中出现了严峻的耦合----思量使用委托来解决下
如果代码中,出现了大量的重复代码----思量使用委托来解决下
四、框架内置的委托Action/Func
这里我们界说了两个相同的委托,
public delegate void DoGodDelegate(object? o);
public delegate void ParameterizedThreadStart(object? o);我们在单独使用这2个委托的时候,并不会遇到什么问题,
我们可以发现无论是doRichard 照旧threadStart执行委托,都是执行的同一个方法;
两个委托做的事儿是千篇一律;
问题
Thread thread = new Thread(threadStart);
//Thread thread1 = new Thread(doRichard); //不允许的;问题:在两个结构,功能完全相同的委托;有可能不能通用的;不太合理???Why??范例不一样~~
委托的本质是一个类,多个委托就是多个不同的类, 这些没有继承关系,所以不能用;
以上问题、微软也发现了;
为了可以或许让委托能通用, 为了不用界说过多的委托;
微软提供了两个类功的委托: Action/Func
Action: 应对了没有返回值的委托场景;
可有可无参数,肯定没有返回值的委托;最多可以有16个参数~~ 16个泛型版本
如果想要有17个参数的委托呢?(自己扩展)
Action<int> action1 = new Action<int>(s => {}); //接收一个int类型参数,没有返回值
Action<int,string> action2 = new Action<int, string>((i,s) => { }); //接收一个int类型参数,没有返回值
Action<int, string, DateTime, object, int, string, DateTime, object, int, string, DateTime, object, int, string, DateTime, object> action3 = null;
Action<int, string, DateTime, object, int, string, DateTime, object, int, string, DateTime, object, int, string, DateTime, object,int> action4 = null;这是一个没有返回值的通用委托---如果所有的人需要使用没有返回值的委托的时候,都用Action, 不用界说委托;委托都是同一个范例; 就可以通用了;
微软既然提供这个委托,自然是希望我们在以后的编码中,都尽大概使用这些,这样就可以统一了委托的范例;
对于以前界说的委托呢? 咋办? 解决不了~~ 这些被称为技术上的汗青包袱,丢不掉~~以后在使用委托的时候,就不要自己界说了,直接使用现有提供的委托即可~~
委托要有返回值呢?
Func:多版本的委托:应对了有返回值的情况;
肯定有返回值的委托;泛型委托Func中的最后一个范例参数,是作为返回值的范例;前面的范例参数,是作为委托的参数;也提供了最多可以有16个参数;
如果需要有17个参数,且有返回值的委托呢? 可以扩展下呗;
Func<int> func = new Func<int>(() => { return 10; }); //一个返回值的委托,没有参数;
Func<int, string> func1 = new Func<int, string>(s => { return "R"; });
Func<int,string,DateTime,object, int, string, DateTime, object, int, string, DateTime, object, int, string, DateTime, object, string> func2 = null;
//17个参数;
Func<int, string, DateTime, object, int, string, DateTime, object, int, string, DateTime, object, int, string, DateTime,object, object, string> func3 = null;
public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, in T17>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17);
public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, in T17, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17);五、委托的嵌套使用,ASP.NET CORE中心件的核心设计----委托的多层嵌套
这里创建一个很底子的一个类
public class DelegateExtension
{
public static void Show()
{
InvokeAction invokeAction = new InvokeAction();
{
}
}
}
public class InvokeAction {
public void ExeMethod()
{
Console.WriteLine("Exec ExeMethod");
}
}问题:想要去在Invoke.Show方法前后,扩展一些业务逻辑.
这里根据我们之前上面拓展出来的知识可以写出来这样的代码
public static void Show()
{
InvokeAction invokeAction = new InvokeAction();
{
Action action = new Action(invokeAction.ExeMethod);
//再次定义委托
{
Func<Action, Action> action2 = new Func<Action, Action>(ExeNextMethod006);
Action action3 = action2.Invoke(action);
action = action3;
Func<Action, Action> action4 = new Func<Action, Action>(ExeNextMethod005);
Action action5 = action4.Invoke(action);
action = action5;
Func<Action, Action> action6 = new Func<Action, Action>(ExeNextMethod004);
Action action7 = action6.Invoke(action);
action = action7;
Func<Action, Action> action8 = new Func<Action, Action>(ExeNextMethod003);
Action action9 = action8.Invoke(action);
action = action9;
Func<Action, Action> action10 = new Func<Action, Action>(ExeNextMethod002);
Action action11 = action10.Invoke(action);
action = action11;
Func<Action, Action> action12 = new Func<Action, Action>(ExeNextMethod001);
Action action13 = action12.Invoke(action);
action = action13;
action.Invoke();
}
}
}
public static Action ExeNextMethod001(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod001 Start");
action();
Console.WriteLine("Exec ExeNextMethod001 End");
});
}
public static Action ExeNextMethod002(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod002 Start");
action();
Console.WriteLine("Exec ExeNextMethod002 End");
});
}
public static Action ExeNextMethod003(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod003 Start");
action();
Console.WriteLine("Exec ExeNextMethod003 End");
});
}
public static Action ExeNextMethod004(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod004 Start");
action();
Console.WriteLine("Exec ExeNextMethod004 End");
});
}
public static Action ExeNextMethod005(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod005 Start");
action();
Console.WriteLine("Exec ExeNextMethod005 End");
});
}
public static Action ExeNextMethod006(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod006 Start");
action();
Console.WriteLine("Exec ExeNextMethod006 End");
});
}
}
public class InvokeAction {
public void ExeMethod()
{
Console.WriteLine("Exec ExeMethod");
}
}我希望无限制的 增加扩展业务逻辑;
再增加一个--界说方法,通过委托包装后去当做参数传递;
现在的代码已经做到了
1.已经做到了职责的单一;
2.但是当前这个 DelegateExtension.Show 方法不太稳固,如果要增加一环,我需要修改DelegateExtension.Show方法
思路:可以把要执行的业务逻辑----特性--封装到特性中去;
public static void Show()
{
InvokeAction invokeAction = new InvokeAction();
{
{
Type type= typeof(InvokeAction);
MethodInfo method = type.GetMethod("ExeMethod");
ExecNextMethod001Attribute attribute1 = method.GetCustomAttribute<ExecNextMethod001Attribute>();
Action action=new Action(()=> { method.Invoke(invokeAction, null); });
action=attribute1.Do(action);
ExecNextMethod002Attribute attribute2 = method.GetCustomAttribute<ExecNextMethod002Attribute>();
action = attribute2.Do(action);
ExecNextMethod003Attribute attribute3 = method.GetCustomAttribute<ExecNextMethod003Attribute>();
action = attribute3.Do(action);
ExecNextMethod004Attribute attribute4 = method.GetCustomAttribute<ExecNextMethod004Attribute>();
action = attribute4.Do(action);
action.Invoke();
}
}
}
public class ExecNextMethod001Attribute: Attribute
{
public Action Do(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod001 Start");
action();
Console.WriteLine("Exec ExeNextMethod001 End");
});
}
}
public class ExecNextMethod002Attribute : Attribute
{
public Action Do(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod002 Start");
action();
Console.WriteLine("Exec ExeNextMethod002 End");
});
}
}
public class ExecNextMethod003Attribute : Attribute
{
public Action Do(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod003 Start");
action();
Console.WriteLine("Exec ExeNextMethod003 End");
});
}
}
public class ExecNextMethod004Attribute : Attribute
{
public Action Do(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod004 Start");
action();
Console.WriteLine("Exec ExeNextMethod004 End");
});
}
}
public class ExecNextMethod005Attribute : Attribute
{
public Action Do(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod005 Start");
action();
Console.WriteLine("Exec ExeNextMethod005 End");
});
}
}
public class ExecNextMethod006Attribute : Attribute
{
public Action Do(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod006 Start");
action();
Console.WriteLine("Exec ExeNextMethod006 End");
});
}
}思路:由于范例不一样,所以只能一个一个的判断;
如果能一次获取所有特性(矛盾,范例不一样,没有办法一次获取所有;????统一范例,如何统一范例?? 来一个父类,让特性继承父类,然后在获取特性的时候,通过父类获取;):放在一个聚集中,要逐个的调用特性的Do方法来包装委托的话,就可以循环执行;
public static void Show()
{
InvokeAction invokeAction = new InvokeAction();
Type type = typeof(InvokeAction);
MethodInfo method = type.GetMethod("ExeMethod");
Action action = new Action(() => { method.Invoke(invokeAction, null); });
IEnumerable<ExecNextMethodAbstractAttribute> attributellist = method.GetCustomAttributes<ExecNextMethodAbstractAttribute>();
foreach (var attribute in attributellist.Reverse())
{
action = attribute.Do(action);
}
action.Invoke();
}
public abstract class ExecNextMethodAbstractAttribute : Attribute
{
public abstract Action Do(Action action);
}
public class ExecNextMethod001Attribute : ExecNextMethodAbstractAttribute
{
public override Action Do(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod001 Start");
action();
Console.WriteLine("Exec ExeNextMethod001 End");
});
}
}
public class ExecNextMethod002Attribute : ExecNextMethodAbstractAttribute
{
public override Action Do(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod002 Start");
action();
Console.WriteLine("Exec ExeNextMethod002 End");
});
}
}
public class ExecNextMethod003Attribute : ExecNextMethodAbstractAttribute
{
public override Action Do(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod003 Start");
action();
Console.WriteLine("Exec ExeNextMethod003 End");
});
}
}
public class ExecNextMethod004Attribute : ExecNextMethodAbstractAttribute
{
public override Action Do(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod004 Start");
action();
Console.WriteLine("Exec ExeNextMethod004 End");
});
}
}
public class ExecNextMethod005Attribute : ExecNextMethodAbstractAttribute
{
public override Action Do(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod005 Start");
action();
Console.WriteLine("Exec ExeNextMethod005 End");
});
}
}
public class ExecNextMethod006Attribute : ExecNextMethodAbstractAttribute
{
public override Action Do(Action action)
{
return new Action(() =>
{
Console.WriteLine("Exec ExeNextMethod006 Start");
action();
Console.WriteLine("Exec ExeNextMethod006 End");
});
}
}这样就可以让我们自己在搭建框架的时候(支持了业务的扩展---AOP扩展---装饰器模式的番外篇),可以让步伐员在使用我们这个框架的时候,更加聚焦业务逻辑;
可以动态增加业务逻辑;
六、多播委托/观察者模式
委托还可以通过+= 把更多的方法包装到委托中来,形成一个方法的执行链子
在执行委托的时候,可以按照+=的顺序,把方法逐个执行;
也提供了-= 操作,可以按照顺序把方法从方法链子中,依次移除;移除按照顺序依次移除,只要是匹配移除一个之后,就不在继承移除了;如果要移除的方法在,委托中不存在,-=就不做任何操作;
委托在+=,-=可以操作哪些方法呢?
[*]静态方法
[*]实例方法
[*]lamdba表达式
[*]普通方法
public void Show()
{
{
Action action = new Action(DoNothing);
action += DoNothing;
action += DoNothing;
action += DoNothing;
action += DoNothing;
action -= DoNothing;
action.Invoke();
}
//委托在+=、 -=可以操作哪些方法呢?
{
Action action = new Action(DoNothing);
action += DoNothingStatic; //+=静态方法
action += new Student().Study; //+=实例方法
action += () => { Console.WriteLine("this is Lambda"); };
//action.Invoke();//都会依次执行
action -= DoNothing; //普通方法
action -= DoNothingStatic;//静态方法
action -= new Student().Study;//实例方法
action -= () => { Console.WriteLine("this is Lambda"); }; //Lambda 表达式
action.Invoke();
}
}
private void DoNothing()
{
Console.WriteLine("This is DoNothing");
}
private static void DoNothingStatic()
{
Console.WriteLine("This is DoNothingStatic");
}
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]