查看: 1973|回复: 0

[ASP.NET教程] 委托

发表于 2017-9-27 08:00:00

第一次写博客,经验不足,有很多地方考虑不到,还请大家海涵。

一. 委托的应用场景?
  1. 把方法当作参数传给其他方法时,需要使用委托。
二. 什么是委托?
1. 委托是一种类型,属于引用类型,定义委托的关键字是 delegate ,在命名空间下以及类的内部都可以定义委托。
2. 声明委托的语法:
a. [访问修饰符] delegate 返回值类型 委托类型名 ([参数])
3. 一个简单的委托应用:

  1. class Program
  2. {
  3. //声明一个委托
  4. delegate void DoSomething();
  5. static void Main(string[] args)
  6. {
  7. //创建一个委托实例,并将符合委托签名的方法赋给它
  8. DoSomething onEvening = LearningEnglish;
  9. //调用需要使用到委托的方法,并将委托实例传给对应的参数
  10. DoSomethingBeforeSleep("Chris", onEvening);
  11. Console.ReadKey();
  12. }
  13. //定义一个符合委托类型DoSomething签名的方法
  14. static void LearningEnglish()
  15. {
  16. Console.WriteLine("背会单词吧。");
  17. }
  18. //需要用到委托的方法
  19. static void DoSomethingBeforeSleep(string name, DoSomething doSomething)
  20. {
  21. Console.WriteLine("睡前做点什么呢?");
  22. doSomething.Invoke(); //等价于 doSomething();
  23. Console.WriteLine($"{name}:我要睡觉了。");
  24. }
  25. }
复制代码

  4. 委托的多种呈现方式:

  1. static void Main(string[] args)
  2. {
  3. #region 常规用法:
  4. //创建一个委托实例,并将符合委托签名的方法赋给它
  5. DoSomething onEvening = LearningEnglish;
  6. //调用需要使用到委托的方法,并将委托实例传给对应的参数
  7. DoSomethingBeforeSleep("Chris", onEvening);
  8. #endregion
  9. #region 使用匿名方法
  10. DoSomethingBeforeSleep("Chris",delegate { Console.WriteLine("背会单词吧。"); });
  11. #endregion
  12. #region 使用Lambda语句
  13. DoSomethingBeforeSleep("Chris", () => { Console.WriteLine("背会单词吧。"); } );
  14. #endregion
  15. #region 使用Lambda表达式
  16. DoSomethingBeforeSleep("Chris", () => Console.WriteLine("背会单词吧。"));
  17. #endregion
  18. Console.ReadKey();
  19. }
复制代码

 5. 通用委托(泛型委托):System.Action 、System.Func、System.Predicate(略)

  1.为了减少自定义委托类型的必要,.NET3.5(C#3.0)包含了一组通用的委托 。

    1.1 Action :代表无参数且没有返回值的方法。  

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. DoSomethingBeforeSleep("Chris", LearningEnglish);
  6. Console.ReadKey();
  7. }
  8. //定义一个符合委托类型 delegate void DoSomething() 签名的方法
  9. static void LearningEnglish()
  10. {
  11. Console.WriteLine("背会单词吧。");
  12. }
  13. //需要用到委托的方法
  14. static void DoSomethingBeforeSleep(string name, Action doSomething) //Action 等价于 delegate void DoSomething() 这个类型的一个委托。
  15. {
  16. Console.WriteLine("睡前做点什么呢?");
  17. doSomething.Invoke();
  18. Console.WriteLine($"{name}:我要睡觉了。");
  19. } 
复制代码

    1.2 Action<>:代表包含请求参数且没有返回值的方法,<>里定义参数的类型和个数。   

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. //调用包含委托的方法
  6. DoSomethingBeforeSleep("Chris", Learnning);
  7. Console.ReadKey();
  8. }
  9. //定义一个符合委托类型 delegate void DoSomething(string parameterName) 签名的方法
  10. static void Learnning(string subjectName)
  11. {
  12. Console.WriteLine($"学会儿{subjectName}吧。");
  13. }
  14. //需要用到委托的方法
  15. static void DoSomethingBeforeSleep(string name, Action<string> doSomething) //Action 等价于 delegate void DoSomething(string parameterName) 这个类型的一个委托。
  16. {
  17. Console.WriteLine("睡前做点什么呢?");
  18. doSomething.Invoke("英语"); //调用这个委托的实例,并传递一个string类型的参数
  19. Console.WriteLine($"{name}:我要睡觉了。");
  20. }
复制代码

    1.3 Func<> :代表有返回值的方法,且<>中最后一个参数始终为返回值类型,之前的参数都为请求参数的类型。

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. int times = 0;
  6. do
  7. {
  8. DoSomething("Chris", GetNowHour);
  9. times++;
  10. } while (times<10);
  11. }
  12. public static int GetNowHour()
  13. {
  14. return new Random().Next(0, 12);
  15. }
  16. public static void DoSomething(string name ,Func<int> whatTime) //Func<int> 等价于委托 delegate int DoSomething();
  17. {
  18. var hour = whatTime.Invoke();
  19. switch (hour)
  20. {
  21. case 5: Console.WriteLine($"{name}该起床");
  22. break;
  23. case 7: Console.WriteLine($"{name}出门");
  24. break;
  25. case 12:
  26. Console.WriteLine($"{name}吃午饭");
  27. break;
  28. default:
  29. Console.WriteLine($"{name}不知道该干什么了。");
  30. break;
  31. }
  32. }
复制代码

 6.多播委托 :一个含有多个方法的委托

  6.1:不要依赖于为委托增加方法时的顺序,虽然有时看起来一致。

  6.2 : 多播委托中只能存储同一类型的委托.

  1. class Program
  2. {
  3. //声明一个委托
  4. internal delegate void DoSomething();
  5. static void Main(string[] args)
  6. {
  7. //创建一个委托实例,并将符合委托签名的方法赋给它
  8. DoSomething onEvening = LearningEnglish;
  9. //多播委托:为一个委托实例赋予多个方法
  10. onEvening += WatchTV;
  11. onEvening += PlayGames;
  12. //调用需要使用到委托的方法,并将委托实例传给对应的参数
  13. DoSomethingBeforeSleep("Chris", onEvening);
  14. Console.ReadKey();
  15. }
  16. //定义一个符合委托类型DoSomething签名的方法
  17. static void LearningEnglish()
  18. {
  19. Console.WriteLine("背会单词吧。");
  20. }
  21. static void WatchTV()
  22. {
  23. Console.WriteLine("看会电视吧。");
  24. }
  25. static void PlayGames()
  26. {
  27. Console.WriteLine("玩会游戏吧。");
  28. }
  29. //需要用到委托的方法
  30. static void DoSomethingBeforeSleep(string name, DoSomething doSomething)
  31. {
  32. Console.WriteLine("睡前做点什么呢?");
  33. doSomething.Invoke(); //等价于 doSomething();
  34. Console.WriteLine($"{name}:我要睡觉了。");
  35. }
复制代码

   6.3 可以通过调用GetInvocationList()方法, 返回当前委托中的所有方法的返回值.

  1. Delegate [] delegate = onEvening.GetInvocationList();
复制代码

   6.4 多次为同一个委托对象赋值时,后者会覆盖前者。

  1. DoSomething onEvening = LearningEnglish;
  2. onEvening = WatchTV; //覆盖LearningEnglish 方法
  3. onEvening = PlayGames; //覆盖 WatchTV 方法
复制代码

   6.5 多播委托中,如果其中某个方法执行时发生异常,则后续的方法不再执行.

  1. class Program
  2. {
  3. //声明一个委托
  4. internal delegate void DoSomething();
  5. static void Main(string[] args)
  6. {
  7. //创建一个委托实例,并将符合委托签名的方法赋给它
  8. DoSomething onEvening = LearningEnglish;
  9. onEvening = WatchTV; //覆盖LearningEnglish 方法
  10. onEvening = PlayGames; //覆盖 WatchTV 方法
  11. //调用需要使用到委托的方法,并将委托实例传给对应的参数
  12. DoSomethingBeforeSleep("Chris", onEvening);
  13. Console.ReadKey();
  14. }
  15. //定义一个符合委托类型DoSomething签名的方法
  16. static void LearningEnglish()
  17. {
  18. Console.WriteLine("背会单词吧。");
  19. }
  20. static void WatchTV()
  21. {
  22. Console.WriteLine("看会电视吧。");
  23. throw new Exception("这里出了一个BUG");
  24. }
  25. static void PlayGames()
  26. {
  27. Console.WriteLine("玩会游戏吧。");
  28. }
  29. //需要用到委托的方法
  30. static void DoSomethingBeforeSleep(string name, DoSomething doSomething)
  31. {
  32. Console.WriteLine("睡前做点什么呢?");
  33. doSomething.Invoke(); //等价于 doSomething();
  34. Console.WriteLine($"{name}:我要睡觉了。");
  35. }
  36. }
复制代码

7. 委托中的协变、逆变、闭包

  7.1 闭包:通过Lambda表达式访问Lambda表达式块外的变量,这称之为闭包,闭包是一个非常好的功能,但如果使用不当,也会非常危险。(引自 C#高级编程 8.3.3)

  1. static void Main(string[] args)
  2. {
  3. int someVal = 5;
  4. Func<int, int> f = x => x + someVal;
  5. Console.WriteLine(f(3));
  6. someVal = 7;
  7. Console.WriteLine(f(3));
  8. Console.ReadKey();
  9. }
复制代码

本篇博客参考:《C#高级编程》、《C#本质论》、《MDSN》、http://www.cnblogs.com/DeepLearing/p/4594518.html



回复

使用道具 举报

关闭

站长推荐上一条 /1 下一条