委托应用及泛型委托和多播委托
一、委托一般作为方法的参数或者返回值,或者使用多播委托(注册多个方法,可以全部触发)
1.示例:根据对于字符串不同的处理方法逻辑 private delegate void PrintString(string str); static void PrintStr( PrintString print,string str ) { print(str); } static void Method1(string str) { Console.WriteLine(str); } static void Method2(string str) { Debug.WriteLine(str); } static void Main(string[] args) { PrintString method = Method1; PrintStr(method,"Test"); method = Method2; PrintStr(method,"Test"); Console.ReadKey(); }
二、泛型委托
Action-Action<T>
class Program { static void PrintString() { Console.WriteLine("hello world."); } static void PrintInt(int i) { Console.WriteLine(i); } static void PrintString(string str) { Console.WriteLine(str); } static void PrintDoubleInt(int i1, int i2) { Console.WriteLine(i1+i2); } static void Main(string[] args) { //Action a = PrintString;//action是系统内置(预定义)的一个委托类型,它可以指向一个没有返回值,没有参数的方法 //Action<int> a=PrintInt;//定义了一个委托类型,这个类型可以指向一个没有返回值,有一个int参数的方法 //Action<string> a = PrintString;//定义了一个委托类型,这个类型可以指向一个没有返回值,有一个string参数的方法 在这里系统会自动寻找匹配的方法 Action<int, int> a = PrintDoubleInt; a(34, 23); Console.ReadKey(); //action可以后面通过泛型去指定action指向的方法的多个参数的类型 ,参数的类型跟action后面声明的委托类型是对应着的 } }
Func<T>
class Program { static int Test1() { return 1; } static int Test2(string str) { Console.WriteLine(str); return 100; } static int Test3(int i, int j) { return i + j; } static void Main(string[] args) { //Func<int> a = Test1;//func中的泛型类型制定的是 方法的返回值类型 //Console.WriteLine(a()); //Func<string, int> a = Test2;//func后面可以跟很多类型,最后一个类型是返回值类型,前面的类型是参数类型,参数类型必须跟指向的方法的参数类型按照顺序对应 Func<int, int, int> a = Test3;//func后面必须指定一个返回值类型,参数类型可以有0-16个,先写参数类型,最后一个是返回值类型 int res = a(1, 5); Console.WriteLine(res); Console.ReadKey(); } }
泛型委托应用:冒泡排序扩展
class Employee { public string Name { get; private set; } public int Salary { get; private set; } public Employee(string name, int salary) { this.Name = name; this.Salary = salary; } //如果e1大于e2的话,返回true,否则返回false public static bool Compare(Employee e1, Employee e2) { if (e1.Salary > e2.Salary) return true; return false; } public override string ToString() { return Name + ":" + Salary; } }
class Program { static void Sort(int[] sortArray) { bool swapped = true; do { swapped = false; for (int i = 0; i < sortArray.Length - 1; i++) { if (sortArray[i] > sortArray[i + 1]) { int temp = sortArray[i]; sortArray[i] = sortArray[i + 1]; sortArray[i + 1] = temp; swapped = true; } } } while (swapped); } static void CommonSort<T>(T[] sortArray, Func<T,T,bool> compareMethod) { bool swapped = true; do { swapped = false; for (int i = 0; i < sortArray.Length - 1; i++) { if (compareMethod(sortArray[i],sortArray[i+1])) { T temp = sortArray[i]; sortArray[i] = sortArray[i + 1]; sortArray[i + 1] = temp; swapped = true; } } } while (swapped); } static void Main(string[] args) { //int[] sortArray = new int[]{123,23,12,3,345,43,53,4}; //Sort(sortArray); //foreach (var temp in sortArray) //{ // Console.Write(temp+" "); //} Employee[] employees = new Employee[] { new Employee("dsf",12), new Employee("435dsf",234), new Employee("234dsf",14), new Employee("ds234f",234), new Employee("dssfdf",90) }; CommonSort<Employee>(employees,Employee.Compare); foreach (Employee em in employees) { Console.WriteLine(em); } Console.ReadKey(); } }
多播委托:(可以注册多个方法给委托,也可以注销已注册的方法)
方法:
static void T1() { Console.WriteLine("ok"); } static void T2() { Console.WriteLine("ook"); } static void T3() { Console.WriteLine("oook"); } static void M1(string msg) { Console.WriteLine(msg); } static void M2(string msg) { Console.WriteLine(msg); } static void M3(string msg) { Console.WriteLine(msg); Console.WriteLine("第3个方法。。"); } static void M4(string msg) { Console.WriteLine(msg); } static void M5(string msg) { Console.WriteLine(msg); }
示例:
class Program { static void Main(string[] args) { #region 多播委托 ////一般第一个要使用=赋值,后续的方法可以使用+=来赋值。 //Action<string> action = M1; //action += M2; //表示添加一个委托的引用 //action += M3; //action += M4; //action += M5;//action -= M3;//表示去除一个委托的引用 if(action!=null){//防止为空,报错 action("xxx");//一次性触发全部的方法。调用顺序不一定哦。
} //Console.ReadKey(); #endregion MyDelegate md = new MyDelegate(T1); //为什么这么写呢?等下取消注释上面的代码反编译之后放截图就知道 md = (MyDelegate)Delegate.Combine(md, new MyDelegate(T2), new MyDelegate(T3)); // md(); 下面的方法是获取所有注册的方法逐个调用 Delegate[] delegates = md.GetInvocationList(); for (int i = 0; i < delegates.Length; i++) { (delegates[i] as MyDelegate)(); } Console.ReadKey(); //使用队列试试 //Queue<MyDelegate> queue = new Queue<MyDelegate>(); //queue.Enqueue(new MyDelegate(T1)); //queue.Enqueue(T2); //queue.Enqueue(T3); //queue.Dequeue(); //queue.Dequeue(); //queue.Dequeue(); }
多播委托反编译:可看到,本质就是调用Delegate.Combine方法组装起来的,调用的时候为什么能全部触发已注册的方法?可以看到编译器调用GetInvocationList方法之后得到委托父类数组循环逐个调用; 事件的本质我们稍后探讨,跟多播密不可分