委托

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

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

 class Program
    {
        //声明一个委托
        delegate void DoSomething();
        static void Main(string[] args)
        {
            //创建一个委托实例,并将符合委托签名的方法赋给它
            DoSomething onEvening = LearningEnglish;
            //调用需要使用到委托的方法,并将委托实例传给对应的参数
            DoSomethingBeforeSleep("Chris", onEvening);

          
            Console.ReadKey();
        }
        //定义一个符合委托类型DoSomething签名的方法
        static void LearningEnglish()
        {
            Console.WriteLine("背会单词吧。");
        }
        //需要用到委托的方法
        static void DoSomethingBeforeSleep(string name, DoSomething doSomething)
        {
            Console.WriteLine("睡前做点什么呢?");

            doSomething.Invoke(); //等价于 doSomething();

            Console.WriteLine($"{name}:我要睡觉了。");
        }
    }

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

 static void Main(string[] args)
        {
            #region 常规用法:

            //创建一个委托实例,并将符合委托签名的方法赋给它
            DoSomething onEvening = LearningEnglish;
            //调用需要使用到委托的方法,并将委托实例传给对应的参数
            DoSomethingBeforeSleep("Chris", onEvening);

            #endregion

            #region 使用匿名方法

            DoSomethingBeforeSleep("Chris",delegate { Console.WriteLine("背会单词吧。"); });

            #endregion

            #region 使用Lambda语句

            DoSomethingBeforeSleep("Chris", () => { Console.WriteLine("背会单词吧。"); } );

            #endregion

            #region 使用Lambda表达式

            DoSomethingBeforeSleep("Chris", () => Console.WriteLine("背会单词吧。"));

            #endregion
            Console.ReadKey();
        }

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

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

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

class Program
    {
        static void Main(string[] args)
        {

            DoSomethingBeforeSleep("Chris", LearningEnglish);
            Console.ReadKey();
        }

        //定义一个符合委托类型 delegate void DoSomething() 签名的方法
        static void LearningEnglish()
        {
            Console.WriteLine("背会单词吧。");
        }

        //需要用到委托的方法
        static void DoSomethingBeforeSleep(string name, Action doSomething) //Action 等价于 delegate void DoSomething() 这个类型的一个委托。
        {
            Console.WriteLine("睡前做点什么呢?");

            doSomething.Invoke();

            Console.WriteLine($"{name}:我要睡觉了。");
        } 

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

 class Program
    {
        static void Main(string[] args)
        {
            //调用包含委托的方法
            DoSomethingBeforeSleep("Chris", Learnning);

            Console.ReadKey();
        }

        //定义一个符合委托类型 delegate void DoSomething(string parameterName) 签名的方法
        static void Learnning(string subjectName)
        {
            Console.WriteLine($"学会儿{subjectName}吧。");
        }

        //需要用到委托的方法
        static void DoSomethingBeforeSleep(string name, Action<string> doSomething) //Action 等价于 delegate void DoSomething(string parameterName) 这个类型的一个委托。
        {
            Console.WriteLine("睡前做点什么呢?");

            doSomething.Invoke("英语"); //调用这个委托的实例,并传递一个string类型的参数

            Console.WriteLine($"{name}:我要睡觉了。");
        }

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

class Program
    {
        static void Main(string[] args)
        {
            int times = 0;
            do
            {
                DoSomething("Chris", GetNowHour);
                times++;
            } while (times<10);
           
        }

        public static int GetNowHour()
        {
            return new Random().Next(0, 12);
        }

        public static void DoSomething(string name ,Func<int> whatTime)  //Func<int> 等价于委托 delegate int DoSomething();
        {
            var hour = whatTime.Invoke();

            switch (hour)
            {
                case 5: Console.WriteLine($"{name}该起床");
                    break;
                case 7: Console.WriteLine($"{name}出门");
                    break;
                case 12:
                    Console.WriteLine($"{name}吃午饭");
                    break;
                default:
                    Console.WriteLine($"{name}不知道该干什么了。");
                    break;
            }
        }

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

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

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

 class Program
    {
        //声明一个委托
        internal delegate void DoSomething();
        static void Main(string[] args)
        {
            //创建一个委托实例,并将符合委托签名的方法赋给它
            DoSomething onEvening = LearningEnglish;

            //多播委托:为一个委托实例赋予多个方法
            onEvening += WatchTV;
            onEvening += PlayGames;

            //调用需要使用到委托的方法,并将委托实例传给对应的参数
            DoSomethingBeforeSleep("Chris", onEvening);

            Console.ReadKey();
        }
        //定义一个符合委托类型DoSomething签名的方法
        static void LearningEnglish()
        {
            Console.WriteLine("背会单词吧。");
        }

        static void WatchTV()
        {
            Console.WriteLine("看会电视吧。");
        }

        static void PlayGames()
        {
            Console.WriteLine("玩会游戏吧。");
        }
        //需要用到委托的方法
        static void DoSomethingBeforeSleep(string name, DoSomething doSomething)
        {
            Console.WriteLine("睡前做点什么呢?");

            doSomething.Invoke(); //等价于 doSomething();

            Console.WriteLine($"{name}:我要睡觉了。");
        }

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

Delegate [] delegate = onEvening.GetInvocationList();

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

  DoSomething onEvening = LearningEnglish;
  onEvening = WatchTV;  //覆盖LearningEnglish 方法
  onEvening = PlayGames; //覆盖 WatchTV 方法

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

 class Program
    {
        //声明一个委托
        internal delegate void DoSomething();
        static void Main(string[] args)
        {
            //创建一个委托实例,并将符合委托签名的方法赋给它
            DoSomething onEvening = LearningEnglish;

            onEvening = WatchTV;  //覆盖LearningEnglish 方法
            onEvening = PlayGames; //覆盖 WatchTV 方法

            //调用需要使用到委托的方法,并将委托实例传给对应的参数
            DoSomethingBeforeSleep("Chris", onEvening);

            Console.ReadKey();
        }
        //定义一个符合委托类型DoSomething签名的方法
        static void LearningEnglish()
        {
            Console.WriteLine("背会单词吧。");
        }

        static void WatchTV()
        {
            Console.WriteLine("看会电视吧。");
            throw new Exception("这里出了一个BUG");
        }

        static void PlayGames()
        {
            Console.WriteLine("玩会游戏吧。");
        }
        //需要用到委托的方法
        static void DoSomethingBeforeSleep(string name, DoSomething doSomething)
        {
            Console.WriteLine("睡前做点什么呢?");

            doSomething.Invoke(); //等价于 doSomething();

            Console.WriteLine($"{name}:我要睡觉了。");
        }
    }

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

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

 static void Main(string[] args)
        {
            int someVal = 5;
            Func<int, int> f = x => x + someVal;
            Console.WriteLine(f(3));
            someVal = 7;
            Console.WriteLine(f(3));

            Console.ReadKey();
        }

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

转载于:https://www.cnblogs.com/coderchris/p/6972133.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值