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

委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递。事件是一种特殊的委托。

类似c++的函数指针,但是他是类型安全的,

  1. 允许将方法作为参数传递。
  2. 可用于定义回调方法。
  3. 委托可以链接在一起。例如,可以对一个事件调用多个方法。

delegate

委托的关键字是 delegate,一个委托相当于一个新的类,可使用访问修饰符 public、private、protected等,作用域同类的修饰符.

定义了委托类型与参数,使得可以将方法当作另一个方法参数来传递。事件是一种特殊的委托。

Delegate至少0个参数,至多32个参数,可以无返回值,也可以指定返回值类型。

定义一个委托,有二个参数,并返回Int类型的值。

  1. delegate int CalculateMethodInvoker(int a, int b);

定义方法,方法参数与返回值与委托保持一致

  1. public class CalculateHelper
  2. {
  3. public static int Sum(int x, int y)
  4. {
  5. return x + y;
  6. }
  7. public static int Multiply(int x, int y)
  8. {
  9. return x * y;
  10. }
  11. }

调用

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. CalculateMethodInvoker calculateSumInvoker = CalculateHelper.Sum;
  6. CalculateMethodInvoker calculateSumInvoker2 = new CalculateMethodInvoker(CalculateHelper.Sum);//实例化一个委托
  7. CalculateMethodInvoker calculateMultiplyInvoker = CalculateHelper.Multiply;
  8. int x = 20, y = 10;
  9. int addResult = calculateSumInvoker(x, y);
  10. int addResult2 = calculateSumInvoker2(x, y);
  11. int invokeResult = calculateSumInvoker.Invoke(x, y);
  12. Console.WriteLine($"x,y相加,得到{addResult},{addResult2},{invokeResult}");
  13. Console.WriteLine($"x,y相乘,得到{calculateMultiplyInvoker(x,y)}");
  14. Console.ReadKey();
  15. }
  16. }

一个委托可以将多个方法链接在一起。也可以移除某个方法

  1. public static void ContactDelegate()
  2. {
  3. CalculateMethodInvoker calculateInvoker = CalculateHelper.Sum;
  4. calculateInvoker += CalculateHelper.Multiply;
  5. int r1 = calculateInvoker(10, 20);
  6. Console.WriteLine($"ContactDelegate:{r1}");
  7. calculateInvoker -= CalculateHelper.Multiply;
  8. int r2 = calculateInvoker(10, 20);
  9. Console.WriteLine($"ContactDelegate:{r2}");
  10. }

Action

Action是无返回值的泛型委托。特点是:至少0个参数,至多16个参数,无返回值。

  1. 调用方法、可以传入参数
    1. public static void ActionParams()
    2. {
    3. Action<int, int> action = new Action<int, int>(Sum);
    4. action(1, 2);
    5. }
    6. public static void Sum(int x, int y)
    7. {
    8. Console.WriteLine($"x+y={x + y}");
    9. }
  2. 使用lambda表达式
    1. public static void ActionLambda()
    2. {
    3. Action<int, int> action = (x, y) =>
    4. {
    5. Console.WriteLine($"x+y={x + y}");
    6. };
    7. action(1, 2);
    8. }

Func

Func是有返回值的泛型委托,Func特点:至少0个参数,至多16个参数,根据返回值泛型返回。必须有返回值,不可void

Func<int> 表示无参,返回值为int的委托

Func<int, int, string> 表示传入参数为int, int。 返回值为string的委托

1.调用方法,传入参数

  1. public static void FuncMethod()
  2. {
  3. Func<int, int, int> fc1 = new Func<int, int, int>(CalculateHelper.Sum);
  4. int result = fc1(1, 2);//调用委托
  5. Console.WriteLine(result);
  6. }

2.使用lambda

  1. public static void FuncLambda()
  2. {
  3. Func<int, int, string> fc = (x, y) => { return (x + y).ToString(); };
  4. string r = fc(1,2);
  5. Console.WriteLine(r);
  6. }

Predicate

predicate 是返回bool型的泛型委托

predicate<int> 表示传入参数为int 返回bool的委托

Predicate有且只有一个参数,返回值固定为bool

1、使用单行lambda,带括号的lambda(可多行代码),独立的方法。都返回bool类型的值。

  1. public static void PredicateBoolean()
  2. {
  3. Point[] points = {
  4. new Point(100, 200),
  5. new Point(150, 250),
  6. new Point(250, 375),
  7. new Point(275, 395),
  8. new Point(295, 450)
  9. };
  10. Predicate<Point> predicate1 = p => p.X * p.Y > 100000;
  11. Predicate<Point> predicate2 = p =>
  12. {
  13. if (p.X * p.Y > 100000)
  14. {
  15. return true;
  16. }
  17. else
  18. {
  19. return false;
  20. }
  21. };
  22. Point first = Array.Find(points, ProductGT10);
  23. Point p1 = Array.Find(points, predicate1);
  24. Point p2 = Array.Find(points, predicate2);
  25. Console.WriteLine("Found: X = {0}, Y = {1}", first.X, first.Y);
  26. Console.WriteLine("Found: X = {0}, Y = {1}", p1.X, p1.Y);
  27. Console.WriteLine("Found: X = {0}, Y = {1}", p2.X, p2.Y);
  28. Console.ReadKey();
  29. }
  30. private static bool ProductGT10(Point p)
  31. {
  32. if (p.X * p.Y > 100000)
  33. {
  34. return true;
  35. }
  36. else
  37. {
  38. return false;
  39. }
  40. }

Array.Find方法,使用Predicate委托搜索Point结构的数组,只有是x和y 字段的乘积大于100000,方法ProductGT10返回true,找到符合要求的元素后停止。

事件

事件自身就是委托类型,由于委托可以绑定调用多个方法,这会给事件的处理带来方便 。类只需要对外公开事件,就可以与外部的其他地方关联,从而实现事件订阅。

1.由于不同的事件要传递的参数不同,我们通过继承EventArgs,

  1. public class KeyPressEventArgs : EventArgs
  2. {
  3. public ConsoleKey PressdKey { get; private set; }
  4. public KeyPressEventArgs(ConsoleKey consoleKey)
  5. {
  6. this.PressdKey = consoleKey;
  7. }
  8. }

2.

带有泛型参数的事件处理委托。

系统函数内置如下委托

  1. public delegate void EventHandler<TEventArgs>(object sender,TEventArgs e); TEventArgs 是一个泛型参数
  1. class App
  2. {
  3. public event EventHandler<KeyPressEventArgs> KeyPressed;
  4. protected virtual void OnSpaceKeyPressed(KeyPressEventArgs e)
  5. {
  6. KeyPressed?.Invoke(this, e);
  7. }
  8. public void StartRun()
  9. {
  10. while (true)
  11. {
  12. ConsoleKeyInfo keyInfo = Console.ReadKey();
  13. if (keyInfo.Key == ConsoleKey.Spacebar)
  14. {
  15. OnSpaceKeyPressed(new KeyPressEventArgs(keyInfo.Key));
  16. }
  17. if (keyInfo.Key == ConsoleKey.Escape)
  18. {
  19. break;
  20. }
  21. }
  22. }
  23. }
  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. Console.WriteLine("空格:输入当前时间");
  6. Console.WriteLine("ESC:退出系统");
  7. App app = new App();
  8. app.KeyPressed += MyApp_SpaceKeyPressed;
  9. app.StartRun();
  10. }
  11. public static void MyApp_SpaceKeyPressed(object sender,KeyPressEventArgs e)
  12. {
  13. Console.WriteLine($"{DateTime.Now.ToLongTimeString()}按下空格键,{e.PressdKey.ToString()}");
  14. }
  15. }

参考