第五节:委托的使用"/>
第五节:委托的使用
一 委托解释
简单说它就是一个能把方法当参数传递的对象,而且还知道怎么调用这个方法,同时也是粒度更小的“接口”(约束了指向方法的签名)。
二 委托简单使用
一个委托类型定义了该类型的实例能调用的一类方法,这些方法含有同样的返回类型 和同样参数(类型和个数相同)。委托和接口一样,可以定义在类的外部。如下定义了一个委托类型 - Calculator:(计算机委托)
delegate int Calculator (int x);
此委托适用于任何有着int返回类型和一个int类型参数的方法,如:
委托的使用public delegate int Calculator(int x);public static int Double(int x){return x * 2;}
2.1 委托调用:
//委托调用,(同类型,同参数类的方法)就能通过委托调用定义的这些方法,不需要实例化//第一种写法Calculator c = new Calculator(Double);int result = c(2);//第二种写法Calculator c1 = Double;int result1 = c(2);
三 用委托实现插件式编程
解释:我们可以利用“ 委托是一个能把方法作为参数传递的对象 ” 这一特点,来实现一种插件式编程。
3.1 例如,我们有一个Utility类,这个类实现一个通用方法(Calculate),用来执行任何有一个整型参数和整型返回值的方法。这样说有点抽象,下面来看一个例子:
namespace MyDelegate
{//定义一个委托类,在传建一个 类型相同,参数类型相同的方法在使用委托public class BaseDelegate{public delegate int Calculator(int x);public static int Double(int x){return x * 2;}}//写一个公共的方法把委托当参数来使用,就可以实现所有int 类型的方法和int 类型的返回值都可以调用这个参数使用public class Utility{public static void Calculate(int[] values, Calculator c){for (int i = 0; i < values.Length; i++) values[i] = c(values[i]);}}
}
3.2 公共方法委托调用
//在这里也可以定义委托 class Program{static void Main(string[] args){int[] values = { 1, 2, 3, 4 };//这是调用了公共方法把委托当初 参数来调用// Double 就是使用了委托Utility.Calculate(values, Double);foreach (int i in values){Console.Write(i + " "); // 2 4 6 8 }Console.ReadKey();}}
四 多播委托
多播委托解释:
所有的委托实例都有多播的功能。所谓多播,就像一群程序员在瞬聘网填好了求职意向后,某天有个公司发布了一个和这些程序员求职意向刚好相匹配的工作,然后这些求职者都被通知了 - “有一份好工作招人啦,你们可以直接申请去上班了!”。也就是说,一个委托实例不仅可以指向一个方法,还可以指向多个方法
例如:多播委托添加/移除案例如下
委托的定义,和可以使用委托的方法public class MyDelegateTest{//先定义一个委托 一个无参返回类型,无参的委托方法public delegate void ProgressReporter();public static void GetMothe1(){Console.WriteLine("我是委托第一个");}public static void GetMothe2(){Console.WriteLine("我是委托第二个");}public static void GetMothe3(){Console.WriteLine("我是委托第三个");}public static void GetMothe4(){Console.WriteLine("我是委托第四个");}public static void GetMothe5(){Console.WriteLine("我是委托第五个");}}
怎么调用委托进行新增移除委托?如下
Console.WriteLine("********** 我在测试多播委托 添加 **************");ProgressReporter delegateTest =GetMothe1;delegateTest += GetMothe2;delegateTest += GetMothe3;delegateTest += GetMothe4;delegateTest += GetMothe5;//Invoke 作用是:调用委托方法,冲第一个到最后一个按顺序来执行delegateTest.Invoke();Console.WriteLine("******** 我在测试多播委托 移除 **********");ProgressReporter delegateTest1 = GetMothe1;delegateTest1 -= GetMothe2;delegateTest1 -= GetMothe3;delegateTest1 -= GetMothe4;delegateTest1 -= GetMothe5;//Invoke 作用是:调用委托方法,冲第一个到最后一个按顺序来执行delegateTest.Invoke();
五 下面来探讨一下 静态方法和实例方法对于委托的区别
当一个类的实例的方法被赋给一个委托对象时,在上下文中不仅要维护这个方法,还要维护这个方法所在的实例。
System.Delegate 类的Target属性指向的就是这个实例
但对于静态方法,System.Delegate 类的Target属性是Null,所以将静态方法赋值给委托时性能更优
六 泛型委托
解释:如果你知道泛型,那么就很容易理解泛型委托,说白了就是含有泛型参数的委托
C# 3.0 新语法在 using 后面加上 static 就不需要在创建类的实例化,可以直接使用该类的所有方法包括属性
using static MyDelegate.BaseDelegate;
using static MyDelegate.GenericDelegate;
using static MyDelegate.MyDelegateTest;
using static MyDelegate.Student;
创建泛型委托代码如下:
/// <summary>/// 泛型委托/// </summary>public class GenericDelegate{/// <summary>/// 泛型委托,返回值 是 T 类型,参数也是 T 类型,/// 只要方法能匹配这个泛型委托方法就可以进行调用/// </summary>/// <param name="a"></param>/// <returns></returns>public delegate T GenericDelegateMothe<T>(T t);//泛型方法给泛型委托调用public static T GenericDelegateInt<T>(T iPaer){Console.WriteLine($"我是 {iPaer.GetType().Name}类型 的泛型委托实现方法");return iPaer;}//普通方法给 泛型委托调用public static string GenericDelegateString(string sPaer){Console.WriteLine($"我是 {sPaer.GetType().Name}类型 的泛型委托实现方法");return sPaer;}}
泛型委托调用
Console.WriteLine("********* 泛型委托 泛型方法的调用 **************** ");GenericDelegateMothe<int> delegateMothe = GenericDelegateInt<int>;delegateMothe.Invoke(7);Console.WriteLine("******** 泛型委托 普通方法的调用 ****************** ");GenericDelegateMothe<string> mothe = GenericDelegateString;mothe.Invoke("你好");总结: 如果使用了泛型委托,应该要使用泛型方法来实现这个泛型委托,而不是用普通方法实现这个泛型委托,
因为 泛型方法可以适用于所有类的方法调用,而不是使用普通方法来用泛型委托, 这样就没意义了,就把泛型委托的扩展性给限制了
六 Func 和 Action 委托
有了泛型委托,就有了一个能适用于任何返回类型和任意参数(类型和合理的个数)的通用委托,Func 和 Action。
如下所示(下面的 in 表示参数,out 表示返回结果):
delegate TResult Func <out TResult> ();
delegate TResult Func <in T, out TResult> (T arg);
delegate TResult Func <in T1, in T2, out TResult> (T1 arg1, T2 arg2); ... 一直到 T16
-----------------------------------------
delegate void Action ();
delegate void Action <in T> (T arg);
delegate void Action <in T1, in T2> (T1 arg1, T2 arg2); ... 一直到 T16
使用 Func <out TResult> () 和 Action<in T>() 的调用
{//使用Fun 来调用 有参数,有返回值的的委托泛型方法(这是普通方法)Func<string, string> func = GenericDelegateString;func.Invoke("我使用 Fun 带返回值的委托方法");//使用泛型委托调用Func<int,int> f = GenericDelegateInt<int>;f.Invoke(98);//是用 Action 来调用 无返回值 有参数的 委托Action<string> action = Show;action.Invoke("刘建峰");}
总结:这里这俩个委托之后,我们就可有不用特意创建委托了带参数,带返回值的就是用 Func <out TResult> (),
带参数,不带返回值的就是用 Action<in T>() 这个委托,
为什么有这来个委托呢?
因为为了统一,不会被搞乱,如果委托定义多了就不知道那个创建的委托可以调用那个方法了,所以微软官方就封装了俩个委托供大家使用
7 委托的兼容
7.1. 委托的类型兼容
delegate void D1();
delegate void D2();D1 d1 = Method1;
D2 d2 = d1;
下面是被允许的:D2 d2 = newD2 (d1);
对于具体相同的目标方法的委托是被视为相等的:delegate void D();D d1 = Method1;
D d2 = Method1;
Console.WriteLine (d1 == d2); // True
同理,对于多播委托,如果含有相同的方法和相同的顺序,也被视为相等。
7.2 参数类型兼容、
在OOP中,任何使用父类的地方均可以用子类代替,这个OOP思想对委托的参数同样有效。如:
delegate void StringAction(string s);
class Program { static void Main() { StringAction sa = new StringAction(ActOnObject); sa("hello");
} static void ActOnObject(object o) { Console.WriteLine(o); // hello }
}
7.3. 返回值类型兼容
delegate object ObjectRetriever();
class Program { static void Main() { ObjectRetriever o = new ObjectRetriever(RetriveString); object result = o(); Console.WriteLine(result); // hello
} static string RetriveString(){ return "hello"; }
}
更多推荐
第五节:委托的使用
发布评论