1.委托概述
委托是一种数据类型,像类一样(可以声明委托类型变量)。方法参数可以是int、string、类类型
void M1(int n){ } √
void M2(string s){ } √
void M3(Person p){ } √
委托就是一种数据类型,用来存放方法的数据类型。
那么委托到底把方法存到哪里了?其实委托还是一个类。把方法包装成了一个委托。
方法是不能直接赋值的,那么能不能声明一个能存放方法的变量呢(委托)。像存储变量一样把方法存储起来。
2.委托的使用
声明委托的方式:delegate 返回值类型 委托类型名(参数) 比如delegate void StringProcess(string s); 注意这里的除了前面的delegate,剩下部分和声明一个函数一样,但是StringProcess不是函数名,而是委托类型名
存储什么样的方法就声明什么类型(方法参数与返回值)的委托。
声明的委托是一种类型,就像int、Person一样,如果要用的话还要声明委托类型的变量,声明委托类型变量的方式:StringProcess f1;
将委托类型变量指向函数 StringProcess sp = new StringProcess(SayHello),这样就可以像调用普通函数一样把sp当成函数用了。委托可以看做是函数的指针。整数可以用整数变量指向它,对象可以用对象变量指向它,函数也可以用委托变量指向它。和直接调用函数的区别:用委托就可以指向任意的函数,哪怕是之前没定义的都可以,而不使用受限于那几种。
将委托类型变量指向函数还可以简化成StringProcess sp = SayHello,编译器帮我们进行了new。但是不能sp=PrintIt(),因为这样就成了函数调用。
3.委托用例
1 class Program 2 { 3 //定义一个委托类型DelegateString 4 public delegate string DelegateString(string text); 5 //定义一个ChangeString类 6 public class ChangeString 7 { 8 //定义一个ChangeStringText方法,包含一个字符串数组和一个委托变量 9 //ChangeText用来接收传进来的方法10 public void ChangeStringText(string[] names,DelegateString ChangeText)11 {12 for (int i = 0; i < names.Length; i++)13 {14 //调用传进来的方法改变字符串15 names[i] = ChangeText(names[i]);16 }17 }18 }19 static void Main(string[] args)20 {21 ChangeString cs=new ChangeString();22 string[] names = { "卡卡西","佐助","鸣人"};23 //调用ChangeStringText方法,把names数组和JoinString方法传进去24 cs.ChangeStringText(names, JoinString);25 //遍历输出改变后的数组26 for (int i = 0; i < names.Length; i++)27 {28 Console.WriteLine(names[i]);29 }30 Console.ReadKey();31 }32 //定义一个NewString方法33 public static string NewString(string name)34 {35 return "----"+name+"----";36 }37 //定义一个JoinString38 public static string JoinString(string name)39 {40 return "★" + name + "★";41 }42 }
4.运行结果
传入NewString方法
传入JoinString方法
匿名方法
使用Delegate的时候很多时候没必要使用一个普通的方法,因为这个方法只有这个Delegate会用,并且只用一次,这时候使用匿名方法最合适。 匿名方法就是没有名字的方法。3就是没有名字的int对象。3+5就是两个匿名int对象的相加,允许匿名对象,就允许匿名方法。
ProcessWordDelegate p = delegate(string s) { Console.WriteLine(s); };知道C#中有匿名方法,看到这种写法知道是匿名函数即可。 匿名方法与lambda表达式最终编译为一个方法。MyDelete md = delegate() { Console.WriteLine("嘎嘎"); }; md();
================================================================
public delegate void SayDelegate(); SayDelegate say = () => { Console.WriteLine("hhh"); }; public delegate int MyDelete2(int num); MyDelete2 md2 = delegate(int number) { return number + 10; }; int result= md2(20); Console.WriteLine(result); Console.ReadKey();================================================================ public delegate string SayDelegate(string n); SayDelegate say = x => x+"好帅"; Console.WriteLine(say("小杨"));=============================================================== T1((x, y, z) => x - y + z); public static void T1(SayDelegate say) { int result = say(10, 20, 30); Console.WriteLine(result); } public delegate int SayDelegate(int n1, int n2, int n3);=============================================================== List<int> list = new List<int>() { 1,2,3,4,5,6,7,8,9}; IEnumerable ieor= list.Where(x=>x>5); foreach (int item in ieor) { Console.WriteLine(item); } Console.ReadKey();==============================================================多播委托*(委托链,委托的组合)
delegate void ProcessWordDelegate(string s) ProcessWordDelegate d = new ProcessWordDelegate(SayHello)+new ProcessWordDelegate(ToLower) 多播委托如何处理返回值? 委托绑定多个方法后,其中一个方法执行发生异常后面的方法还会继续执行吗?不会! 一个重要的方法GetInvocationList();//返回一个Delegate[]类型。Delegate类是一个抽象类,是所有委托的父类。 组合的委托必须是同一个类型 相当于创建了一个按照组合的顺序依次调用的新委托对象。 委托的组合一般是给事件用的,用普通的委托的时候很少用
为委托的增减方法
d+=SayHello,为委托增加一个方法,不要感觉奇怪,因为它就是d=d+ SayHello d-=SayHello,将方法从委托中移除。 Delegate.Combine();
委托的一些应用:
凡是需要回调的地方都能用到委托。 自定义类(控件、通信类……(事件)) 多线程 窗体之间回传值 正则表达式中替换Email掩码Replace()委托的本质1(*)
其实就是一个类把方法包装了一下,委托都继承自System.MulticastDelegate,而System.MulticastDelegate又继承自System.Delegate 多播委托就是有一个委托数组,依次调用。
class Program { static void Main(string[] args) { UpdateDelegate upde = M1; upde += M2; upde += M3; upde -= M2; upde = M4; upde();
Console.ReadKey(); //输出 M1 M2 M3 M4 } public static void M1() { Console.WriteLine("M1"); } public static void M2() { Console.WriteLine("M2"); } public static void M3() { Console.WriteLine("M3"); } public static void M4() { Console.WriteLine("M4"); } } public delegate void UpdateDelegate();===================================================================
ResultDelegate M1 = T1; M1 += T2; M1 += T3; M1 += T4; int r = M1(); Console.WriteLine(r); Console.ReadKey(); //输出M4 public static int T1() { return 1; } public static int T2() { return 2; } public static int T3() { return 3; } public static int T4() { return 4; } public delegate int ResultDelegate();=========================================================== Delegate[]des= M1.GetInvocationList(); foreach (Delegate item in des) { ResultDelegate res = item as ResultDelegate; Console.WriteLine(res()); }=============================================================单独拿到里面每个方法事件(通过委托实现的,委托才是事件能正常执行的核心内容)
事件语法:event ProcessWordDelegate 例子 OnInt 加了event关键字实现事件机制的好处:用了event事件,不可以修改事件已经注册的值;不可以冒充进行事件通知了。在IntUC类外部就不能通过OnInt(3)的方式调用注册的委托了。只能+=、-=!
事件本质论
event会自动生成一个private delegate变量和两个函数: add和remove,C#编译器用这两个方法支持+=和-=操作符 (*)。C#<>.Net。 public event MyDelegate OnEvent; 内部实现是(示例性) private MyDelegate OnEvent; public void Add(MyDelegate d) { OnEvent+=d; } public void Remove(MyDelegate d) { OnEvent-=d; } 因为OnEvent是private的,所以在类外部不能OnEvent(1)触发事件,但是在类内部可以。 public的方法只有Add和Remove,所以只能+=、-=,其他的操作都是不可以的。
委托和事件的区别(常考)
委托和事件没有可比性,因为委托是数据类型,事件是对象(可以理解为对委托变量的封装。),下面说的是委托的对象(用委托方式实现的事件)和(标准的event方式实现)事件的区别。事件的内部是用委托实现的。(举例子:三种实现事件方式的区别(直接用委托实现、用私有委托+公有方法模拟事件,直接用event事件实现)) 因为对于事件来讲,外部只能“注册自己+=、注销自己-=”,外界不可以注销其他的注册者,外界不可以主动触发事件,因此如果用Delegate就没法进行上面的控制,因此诞生了事件这种语法。add、remove。 事件是用来阉割委托实例的。事件只能add、remove自己,不能赋值。事件只能+=、-=,不能=、不能外部触发事件。