委托到匿名方法到lambda表达式

2018-06-22 07:45:47来源:未知 阅读 ()

新老客户大回馈,云服务器低至5折

什么是委托

一个典型的例子,当一个方法的整体是相对固定不变的,而一小部份发生了变化,在没有委托这个东西有时候,我们通常的做法是:传一个变量到方法里,方法根据这个参数值来判断这些变化的部份的具体执行,说得很抽象,整个栗子:

using System;

namespace DemoDelegate
{
    class Program
    {
        static void Main(string[] args)
        {
            string input = Console.ReadLine();
            string result = HandleString(input, "trim");
            Console.WriteLine("没有委托时,我也能达到目的。result=" + result);

        }

        /// <summary>
        /// 将输入的内容前,追加上时间,再做相应的处理
        /// </summary>
        /// <param name="ActoinType"></param>
        /// <returns></returns>
        private static string HandleString(string input, string ActoinType)
        {
            switch (ActoinType)
            {
                case "trim":
                    input = input.Trim();
                    break;
                case "toLowerCase":
                    input = input.ToLower();
                    break;
                case "toUpperCase":
                    input = input.ToUpper();
                    break;
                default:
                    break;
            }
            input = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ffffff") + input;//这就是所说的固定不变的操作
            return input;
        }
    }
}

ps:以上代码中存在不足,看完或者会想:何不先将要处理的变化的那部分在main中进行处理,再调用。回答是:当方法HandleString足够复杂,上下文紧扣时,这个法想就要作罢了。

而按照面向对象封装的思想,这很明显是不符合扩展开放要求的。这时候自然就想,能不能将那变化的部份,以一个方法的形式传进去呢?灯灯灯灯!委托出现

想法:HandleString接收这个变化部份的方法叫什么类型呢?肯定不是将一个方法的调用写在参数里,因为这样就相当于将处理结果给了HandleString。它应该是一个新的数据类型:自己定义的一个类型。那么,先看个傻x问题:我们怎么定义一个类:

    class CatInfo
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }

class本身是一个关键字,那们我们就用delegate来做为定义一个方法类的类型

        public delegate string WhatToDo(string input);

这时候,delete 就想当于class关键字,而这个类,不是平时定义的类那样,有属性,字段,方法。它只是定义了一类方法,如例子,这类方法是一定返回string,方法签名中是输入一个string。这种定义一类方法的方法,就叫委托了。

再看下傻x问题,我们怎么实例化一个类。

            CatInfo info = new CatInfo();

同理地,我们这个实例化一个委托

        public static string Method1(string input)
        {
            string result = "我就是一个普通的方法,返回string。输入参数也是一个string,我的输入值是:" + input;
            Console.WriteLine(result);
            return result;

        }

        WhatToDo instrnceOfWhatToDo = Method1;

是的,没有new关键字,类型 类型实例=具体值(即int a=1)就可以,仔细理解下,它无非就是一个方法类型(委托),为它赋值指向了某一个方法嘛。这时候,理解一个完整的栗子就不难了:

using System;

namespace DemoDelegate
{
    class Program
    {
        public delegate string WhatToDo(string input);
        static void Main(string[] args)
        {
            WhatToDo instrnceOfWhatToDo = DoTrim;

            string input = Console.ReadLine();
            string result = HandleString(input,instrnceOfWhatToDo);
            Console.WriteLine("我会有相同的输出结果。result=" + result);

        }

        public static string DoTrim(string input)
        {
            string result = input.Trim();//脑补这里有很复杂的逻辑要处理
            return result;

        }


        private static string HandleString(string input, WhatToDo TheInstanceOfWhatToDo)
        {
            input = TheInstanceOfWhatToDo(input);
            return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ffffff") + input;

        }
    }
}

总结下:委托,就是具有除方法名外的其它签名信息(输入参数个数和类型、返回参数类型)均相同的方法类型定义

 

有什么用

上面的栗子中,不易体现出委托的用途,但也不难体会出来一点眉目:它有对方法的颗粒数进行拆解的作用。至少像上面例子中,不再需根据ActoinType参数进行一堆判断,有更多变化时,不会违反开闭原则。根据定义好的WhatToDo,写个方法赋给这个委托的实例去调就便可。(当然这样每次扩展,都得定义一个方法的做法很麻烦,并且也没多少重用的可能性。不必担心,后面有简单写法,先挖个坑。

 

-----------------------------------------来个恶心的分隔线------------------------------------------------

什么是事件??后面再说明,再挖个坑,日后来填。

 

 -----------------------------------------分隔线 again------------------------------------------------

 

委托变成匿名方法

基本功理解了,接下来便到了委托的具体玩法。填上前面埋的第一个坑。

要做一个委托,得声名一个一个委托类型,再有一个实例,再有这个实例指向的方法。引用papi酱的话“你说虐不虐?虐不虐?虐啊!”

至少,.net framework为我们做了一点点工作。因为方法的输入参数有限,那么.net framework可以帮我们定义好委托类型嘛!好好利用泛型便行。

它就是Func和Action,Func有返回值,Action 无返回值,看下定义:

Func<TResult>

Func<T, TResult>

Func<T1,T2, TResult>

Func<T1,T2,T3 TResult>

.....

Func就是定义好N个多重载的委托定义(N好大,反正使用也不可能一个方法个有那么多输入参数)。从没有输入参数,返回TResult,到有n个输入参数,返回TResult,都定义好的。

见栗子

        static void Main(string[] args)
        {
            Func<string, DateTime, decimal, string> Method1 = MyMethod;
            Method1("张三", DateTime.Now, (decimal)18.00);

        }

        public static string MyMethod(string parms1, DateTime parms2, decimal parms3)
        {
            return "我是一个由string datetim decimal作为输入参数,返回string的方法";
        }

跟委托最传统的写法没多少区别吧,只是少了定义一个委托类型。直接使用.net framework定义好的Func而已。

同理,Action也是定义好的委托,只不过没返回类型。

Action

Action<T1>

Action<T1,T2>

Action<T1,T2,T3>

还是得上栗子,即使太好理解了:

        static void Main(string[] args)
        {
            Action<string, DateTime, decimal> Method1 = MyMethod;
            Method1("张三", DateTime.Now, (decimal)18.00);

        }

        public static void MyMethod(string parms1, DateTime parms2, decimal parms3)
        {
             Console.WriteLine("我是一个由string datetim decimal string作为输入参数,没有返回值的方法");
        }

 

 -----------------------------------------分隔线 again and  again------------------------------------------------

委托的变化肯定不仅仅是.net framework帮我们定义好几个委托类型便完事。这时候,匿名方法出场。

我就不定义委托类型啦,用上面的Func,即学即用嘛。

using System;
namespace Demo匿名方法
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int, int, int> myMethodPlus = delegate (int a, int b) { return a + b; };
            Func<int, int, int> myMethodDivision = delegate (int a, int b)
            {
                if (b==0)
                {
                    return 0;
                }
                return a / b;
            };
        }
    }
}

这样的写法就很优美了,不用单独定义一个个方法,直接可以将方法体写在委托实例等于号后面。因为这个方法的重用机会接近0。这个叫匿名方法的东西,因为它没有方法名,却有输入参数,返回值,则此得名。

PS.我真的很难记住它的语法,因为工作中少用。最常用的是什么?看下面:

 

匿名方法变成lambda表达式

别想着匿名方法就很优美,C#的语法糖so sweet。

我们有lambda表达式,这个lambda,就是高中数学接触的那个希腊符号λ。让委托写得更赏心悦目。

using System;

namespace DemoLambda
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int, int, int> myMethodPlus = (int a, int b) => { return a + b; };
            Func<int, int, int> myMethodDivision = (int a, int b) =>
            {
                if (b == 0)
                {
                    return 0;
                }
                return a / b;
            };
            int result1 = myMethodPlus(1, 1);
            int result2 = myMethodDivision(4, 2);
        }
    }
}

没错。连那个一开始就要百度翻译的delegate关键字都不见了,用=>代替。语法就是(参数1,参数2,可以一个参数都没有就写个括号)=>{方法体};

到这里,看懂了实现GetEnumlator方法的那些Where(Func<T,bool>),OrderBy(Func(T,TKey)的原理了吧。

 

后记:

      做了程序猿那么多年,一直从这里学习东西,却没有分享过。终于有空第一次写blog。错误之处,多谢提出更正。

 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:二维码生成

下一篇:二维码生成2