委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递。事件是一种特殊的委托。
1.委托的声明
(1). delegate
delegate我们常用到的一种声明
Delegate至少0个参数,至多32个参数,可以无返回值,也可以指定返回值类型。
例:public delegate int MethodtDelegate(int x, int y);表示有两个参数,并返回int型。
(2). Action
Action是无返回值的泛型委托。
Action 表示无参,无返回值的委托
Action<int,string> 表示有传入参数int,string无返回值的委托
Action<int,string,bool> 表示有传入参数int,string,bool无返回值的委托
Action<int,int,int,int> 表示有传入4个int型参数,无返回值的委托
Action至少0个参数,至多16个参数,无返回值。
例:
public void Test<T>(Action<T> action,T p){action(p);}
(3). Func
Func是有返回值的泛型委托
Func<int> 表示无参,返回值为int的委托
Func<object,string,int> 表示传入参数为object, string 返回值为int的委托
Func<object,string,int> 表示传入参数为object, string 返回值为int的委托
Func<T1,T2,,T3,int> 表示传入参数为T1,T2,,T3(泛型)返回值为int的委托
Func至少0个参数,至多16个参数,根据返回值泛型返回。必须有返回值,不可void
例:
public int Test<T1,T2>(Func<T1,T2,int>func,T1 a,T2 b){return func(a, b);}
(4) .predicate
predicate 是返回bool型的泛型委托
predicate<int> 表示传入参数为int 返回bool的委托
Predicate有且只有一个参数,返回值固定为bool
例:public delegate bool Predicate<T> (T obj)
2.委托的使用
(1).Delegate的使用
public delegate int MethodDelegate(int x, int y);private static MethodDelegate method;static void Main(string[] args){method = new MethodDelegate(Add);Console.WriteLine(method(10,20));Console.ReadKey();}private static int Add(int x, int y){return x + y;}
(2).Action的使用
static void Main(string[] args){Test<string>(Action,"Hello World!");Test<int>(Action, 1000);Test<string>(p => { Console.WriteLine("{0}", p); }, "Hello World");//使用Lambda表达式定义委托 Console.ReadKey();}public static void Test<T>(Action<T> action, T p){action(p);}private static void Action(string s){Console.WriteLine(s);}private static void Action(int s){Console.WriteLine(s);}
可以使用 Action<T1, T2, T3, T4> 委托以参数形式传递方法,而不用显式声明自定义的委托。 封装的方法必须与此委托定义的方法签名相对应。 也就是说,封装的方法必须具有四个均通过值传递给它的参数,并且不能返回值。 (在 C# 中,该方法必须返回 void)通常,这种方法用于执行某个操作。
(3).Func的使用
static void Main(string[] args){Console.WriteLine(Test<int,int>(Fun,100,200));Console.ReadKey();}public static int Test<T1, T2>(Func<T1, T2, int> func, T1 a, T2 b){return func(a, b);}private static int Fun(int a, int b){return a + b;}
(4). predicate的使用
泛型委托:表示定义一组条件并确定指定对象是否符合这些条件的方法。此委托由 Array 和 List 类的几种方法使用,用于在集合中搜索元素。
static void Main(string[] args){Point[] points = { new Point(100, 200), new Point(150, 250), new Point(250, 375), new Point(275, 395), new Point(295, 450) };Point first = Array.Find(points, ProductGT10);Console.WriteLine("Found: X = {0}, Y = {1}", first.X, first.Y);Console.ReadKey();}private static bool ProductGT10(Point p){if (p.X * p.Y > 100000){return true;}else{return false;}}
使用带有 Array.Find 方法的 Predicate 委托搜索 Point 结构的数组。如果 X 和 Y 字段的乘积大于 100,000,此委托表示的方法 ProductGT10 将返回 true。Find 方法为数组的每个元素调用此委托,在符合测试条件的第一个点处停止。
3.委托的清空
(1).在类中申明清空委托方法,依次循环去除委托引用。
方法如下:
public MethodDelegate OnDelegate; public void ClearDelegate() { while (this.OnDelegate != null) { this.OnDelegate -= this.OnDelegate; } }
(2).如果在类中没有申明清空委托的方法,我们可以利用GetInvocationList查询出委托引用,然后进行去除。
方法如下:
public MethodDelegate OnDelegate; static void Main(string[] args){Program test = new Program();if (test.OnDelegate != null) { System.Delegate[] dels = test.OnDelegate.GetInvocationList(); for (int i = 0; i < dels.Length; i++) {test.OnDelegate -= dels[i] as MethodDelegate;}}}
4.委托的特点
委托类似于 C++ 函数指针,但它们是类型安全的。
委托允许将方法作为参数进行传递。
委托可用于定义回调方法。
委托可以链接在一起;例如,可以对一个事件调用多个方法。
方法不必与委托签名完全匹配。
5.总结:
Delegate至少0个参数,至多32个参数,可以无返回值,也可以指定返回值类型
Func可以接受0个至16个传入参数,必须具有返回值
Action可以接受0个至16个传入参数,无返回值
Predicate只能接受一个传入参数,返回值为bool类型
详细参考:http://www.fengfly.com/plus/view-209140-1.html
http://www.cnblogs.com/foolishfox/archive/2010/09/16/1827964.html
附:
Event & Delegate
An Event declaration adds a layer of abstraction and protection on the delegate instance. This protection prevents clients of the delegate from resetting the delegate and its invocation list and only allows adding or removing targets from the invocation list.
Delegate对应到设计模式中的代理模式,而event则对应到观察者模式。
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5:
6: namespace ConsoleApplication1
7: {
8: class Program
9: {
10: public class Test
11: {
12: public delegate void WriteName(string name); //定义委托
13: public static event WriteName WriteNameEvent; //定义事件
14: }
15:
16: static Action<string> WriteNameAction;//Action是参数从0到4,返回类型为void(即没有返回值)的委托
17: static Func<string, int> WriteNameFunction;//Func的参数从1到5个,有返回值的委托,最后一个是返回类型
18:
19: static void Main(string[] args)
20: {
21: Test.WriteName myDelegate = x => { Console.WriteLine("abc,{0}!", x); }; // 使用 Lambda 表达式
22: myDelegate("teststring");
23:
24: Test.WriteName w = (string name) => { Console.WriteLine("Hello,{0}!", name); };//使用匿名委托
25: w("Jimmy");
26:
27: Test.WriteNameEvent += (string name) => { Console.WriteLine("Hello,{0}!", name); };//使用匿名委托
28: Test.WriteNameEvent += delegate(string name) { Console.Write("test"); }; //使用匿名方法(.net 2.0)
29:
30: WriteNameAction = HelloWrite; // 匿名委托,和这个一样:WriteNameAction = new Action<string>(HelloWrite);
31: WriteNameAction("test");
32:
33: WriteNameAction = (string name) => { Console.WriteLine("hello,{0}!", name); };//使用匿名委托
34: WriteNameAction("test2");
35:
36:
37: WriteNameFunction = HelloWrite2; // 匿名委托,和这个一样:WriteNameFunction = new Func<string, int>(HelloWrite2);
38: Console.WriteLine(WriteNameFunction("test3"));
39:
40: Predicate<int[]> preTest = i => i.Length == 10;
41:
42: Console.Read();
43:
44: }
45:
46: static List<String> listString = new List<String>()
47: {
48: "One","Two","Three","Four","Fice","Six","Seven","Eight","Nine","Ten"
49: };
50:
51: static List<String> GetFirstStringFromList()
52: {
53: string str = GetStringList(a => { return a.Length <= 3 && a.Contains('S'); });// 使用 Predicate 泛型委托
54:
55: return listString.FindAll((c) => { return c.Length <= 3; });// 使用 Predicate 泛型委托
56: }
57:
58: static String GetStringList(Predicate<String> p) // 使用 Predicate 泛型委托
59: {
60: foreach (string item in listString)
61: {
62: if (p(item))
63: return item;
64: }
65: return null;
66: }
67:
68: static void HelloWrite(string name)
69: {
70: Console.WriteLine("Hello world,{0}!", name);
71: }
72:
73: static int HelloWrite2(string name)
74: {
75: Console.WriteLine("Hello world,{0}!", name);
76: return 1;
77: }
78: }
79: }
- delegate example
使用delegate的目的是在方法中传递方法指针。通过声明delegate的方法签名,可以在运行时在符合delegate方法签名的方法中选择要执行的方法。
- Event example
Event是一种特殊类型的delegate,使用Event可以很方便的实现观察者模式。
- Action example
Action是一种语法糖,它是一种不需要提前声明的delegate,使得delegate的使用更加方便,局限性就是不能定义返回值。(Func<> Delegates是一种可以定义返回值的语法糖)。
What are the differences between delegates and events?
An Event declaration adds a layer of abstraction and protection on the delegate instance. This protection prevents clients of the delegate from resetting the delegate and its invocation list and only allows adding or removing targets from the invocation list.
If course, this protection layer also prevents "clients" (code outside the defining class/struct) from invokingthe delegate, and from obtaining in any way the delegate object "behind" the event.
来源:
http://ariequ.github.io/blog/2014/09/19/delegate-event-action/
http://www.cnblogs.com/mainz/archive/2011/03/11/1981201.html
http://www.cnblogs.com/akwwl/p/3232679.html