您的位置:首页 > 编程语言 > C#

C#委托介绍(delegate、Action、Func、predicate)(一)

2017-05-31 16:01 1006 查看
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递。事件是一种特殊的委托。

  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方法签名的方法中选择要执行的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ModernLanguageConstructs
{
class Program
{
// Part 1 - Explicit declaration of a delegate
//(helps a compiler ensure type safety)
public delegate double delegateConvertTemperature(double sourceTemp);

// A sample class to play with
class TemperatureConverterImp
{
// Part 2 - Will be attached to a delegate later in the code
public double ConvertToFahrenheit(double celsius)
{
return (celsius * 9.0/5.0) + 32.0;
}

//  Part 3 - Will be attached to a delegate later in the code
public double ConvertToCelsius(double fahrenheit)
{
return (fahrenheit - 32.0) * 5.0 / 9.0;
}
}

static void Main(string[] args)
{
//  Part 4 - Instantiate the main object
TemperatureConverterImp obj = new TemperatureConverterImp();

//  Part 5 - Intantiate delegate #1
delegateConvertTemperature delConvertToFahrenheit =
new delegateConvertTemperature(obj.ConvertToFahrenheit);

//  Part 6 - Intantiate delegate #2
delegateConvertTemperature delConvertToCelsius =
new delegateConvertTemperature(obj.ConvertToCelsius);

// Use delegates to accomplish work

//  Part 7 - delegate #1
double celsius = 0.0;
double fahrenheit = delConvertToFahrenheit(celsius);
string msg1 = string.Format("Celsius = {0}, Fahrenheit = {1}",
celsius, fahrenheit);
Console.WriteLine(msg1);

//  Part 8 - delegate #2
fahrenheit = 212.0;
celsius = delConvertToCelsius(fahrenheit);
string msg2 = string.Format("Celsius = {0}, Fahrenheit = {1}",
celsius, fahrenheit);
Console.WriteLine(msg2);
}
}
}



Event example

Event是一种特殊类型的delegate,使用Event可以很方便的实现观察者模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class SampleEventArgs
{
public SampleEventArgs(string s) { Text = s; }
public String Text {get; private set;} // readonly
}
public class Publisher
{
// Declare the delegate (if using non-generic pattern).
public delegate void SampleEventHandler(object sender, SampleEventArgs e);

// Declare the event.
public event SampleEventHandler SampleEvent;

// Wrap the event in a protected virtual method
// to enable derived classes to raise the event.
protected virtual void RaiseSampleEvent()
{
// Raise the event by using the () operator.
if (SampleEvent != null)
SampleEvent(this, new SampleEventArgs("Hello"));
}
}

Action example

Action是一种语法糖,它是一种不需要提前声明的delegate,使得delegate的使用更加方便,局限性就是不能定义返回值。(Func<> Delegates是一种可以定义返回值的语法糖)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2223
24
25
26
27
28
29
30
31
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ModernLanguageConstructs
{
class Program
{
static void Main(string[] args)
{
// Part 1 - First action that takes an int and converts it to hex
Action<int> displayHex = delegate(int intValue)
{
Console.WriteLine(intValue.ToString("X"));
};

// Part 2 - Second action that takes a hex string and
// converts it to an int
Action<string> displayInteger = delegate(string hexValue)
{
Console.WriteLine(int.Parse(hexValue,
System.Globalization.NumberStyles.HexNumber));
};

// Part 3 - exercise Action methods
displayHex(16);
displayInteger("10");
}
}
}


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 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息