xml地图|网站地图|网站标签 [设为首页] [加入收藏]

【必威】委托到匿名方法到lambda表达式

什么是委托

平时我们如果要用到委托一般都是先声明一个委托类型,比如:

平时我们如果要用到委托一般都是先声明一个委托类型,比如:

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

private delegate string Say();
private delegate string Say();
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;        }    }}

string说明适用于这个委托的方法的返回类型是string类型,委托名Say后面没有参数,说明对应的方法也就没有传入参数。

string说明适用于这个委托的方法的返回类型是string类型,委托名Say后面没有参数,说明对应的方法也就没有传入参数。

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

写一个适用于该委托的方法:

写一个适用于该委托的方法:

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

     public static string SayHello()
        {
            return "Hello";
        }
     public static string SayHello()
        {
            return "Hello";
        }

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

最后调用:

最后调用:

    class CatInfo    {        public int ID { get; set; }        public string Name { get; set; }    }
       static void Main(string[] args)
        {
            Say say = SayHello;
            Console.WriteLine(say());
        }
       static void Main(string[] args)
        {
            Say say = SayHello;
            Console.WriteLine(say());
        }

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

这里我们先声明委托,然后再将方法传给该委托。有没有办法可以不定义委托变量呢?

这里我们先声明委托,然后再将方法传给该委托。有没有办法可以不定义委托变量呢?

        public delegate string WhatToDo(string input);

答案是肯定的,我们可以用Func.

答案是肯定的,我们可以用Func.

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

Func是.NET里面的内置委托,它有很多重载。

Func是.NET里面的内置委托,它有很多重载。

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

Func<TResult>:没有传入参数,返回类型为TResult的委托。就像我们上面的Say委托,就可以用Func<string>来替代,调用如下:

Func<TResult>:没有传入参数,返回类型为TResult的委托。就像我们上面的Say委托,就可以用Func<string>来替代,调用如下:

            CatInfo info = new CatInfo();
      static void Main(string[] args)
        {
            Func<string> say = SayHello;
            //Say say = SayHello;
            Console.WriteLine(say());
        }
      static void Main(string[] args)
        {
            Func<string> say = SayHello;
            //Say say = SayHello;
            Console.WriteLine(say());
        }

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

怎么样,有了Func很简单吧。看一下Func别的重载。

怎么样,有了Func很简单吧。看一下Func别的重载。

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

Func<T, TResult> 委托:有一个传入参数T,返回类型为TResult的委托。如:

Func<T, TResult> 委托:有一个传入参数T,返回类型为TResult的委托。如:

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

     //委托 传入参数类型为string,方法返回类型为int
     Func<string, int> a = Count;

      //对应方法
        public int Count(string num)
        {
            return Convert.ToInt32(num);
        }
     //委托 传入参数类型为string,方法返回类型为int
     Func<string, int> a = Count;

      //对应方法
        public int Count(string num)
        {
            return Convert.ToInt32(num);
        }
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;            return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ffffff") + input;        }    }}

Func<T1, T2, TResult> 委托:有两个传入参数:T1T2,返回类型为TResult

Func<T1, T2, TResult> 委托:有两个传入参数:T1T2,返回类型为TResult

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

类似的还有Func(T1, T2, T3, TResult) 委托、Func(T1, T2, T3, T4, TResult) 委托等。用法差不多,都是前面为方法的传入参数,最后一个为方法的返回类型。

类似的还有Func(T1, T2, T3, TResult) 委托、Func(T1, T2, T3, T4, TResult) 委托等。用法差不多,都是前面为方法的传入参数,最后一个为方法的返回类型。

有什么用

Func也可以与匿名方法一起使用如:

Func也可以与匿名方法一起使用如:

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

必威 1

必威 2

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

        public static void Main()
        {
            Func<string, int, string[]> extractMeth = delegate(string s, int i)
            {
                char[] delimiters = new char[] { ' ' };
                return i > 0 ? s.Split(delimiters, i) : s.Split(delimiters);
            };

            string title = "The Scarlet Letter";
            // Use Func instance to call ExtractWords method and display result
            foreach (string word in extractMeth(title, 5))
                Console.WriteLine(word);
        }
        public static void Main()
        {
            Func<string, int, string[]> extractMeth = delegate(string s, int i)
            {
                char[] delimiters = new char[] { ' ' };
                return i > 0 ? s.Split(delimiters, i) : s.Split(delimiters);
            };

            string title = "The Scarlet Letter";
            // Use Func instance to call ExtractWords method and display result
            foreach (string word in extractMeth(title, 5))
                Console.WriteLine(word);
        }

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

必威 3

必威 4

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

同样它也可以接 lambda 表达式

同样它也可以接 lambda 表达式

委托变成匿名方法

必威 5

必威 6

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

  public static void Main()
   {
      char[] separators = new char[] {' '};
      Func<string, int, string[]> extract = (s, i) => 
           i > 0 ? s.Split(separators, i) : s.Split(separators) ;

      string title = "The Scarlet Letter";
      // Use Func instance to call ExtractWords method and display result
      foreach (string word in extract(title, 5))
         Console.WriteLine(word);
   }
  public static void Main()
   {
      char[] separators = new char[] {' '};
      Func<string, int, string[]> extract = (s, i) => 
           i > 0 ? s.Split(separators, i) : s.Split(separators) ;

      string title = "The Scarlet Letter";
      // Use Func instance to call ExtractWords method and display result
      foreach (string word in extract(title, 5))
         Console.WriteLine(word);
   }

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

必威 7

必威 8

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

 Func都是有返回类型的,如果我们的方法没有返回类型该怎么办呢?铛铛铛,这时Action就要粉墨登场了。

 Func都是有返回类型的,如果我们的方法没有返回类型该怎么办呢?铛铛铛,这时Action就要粉墨登场了。

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

Action 委托:没有传入参数,也没有返回类型,即Void。如:

Action 委托:没有传入参数,也没有返回类型,即Void。如:

Func<TResult>

必威 9

必威 10

Func<T, TResult>

       static void Main(string[] args)
        {
            Action say = SayHello;
            say();
        }
        public static void SayHello( )
        {
           Console.WriteLine("Say Hello");
        }
       static void Main(string[] args)
        {
            Action say = SayHello;
            say();
        }
        public static void SayHello( )
        {
           Console.WriteLine("Say Hello");
        }

Func<T1,T2, TResult>

必威 11

必威 12

Func<T1,T2,T3 TResult>

Action<T> 委托:传入参数为T,没有返回类型。如:

Action<T> 委托:传入参数为T,没有返回类型。如:

.....

必威 13

必威 14

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

      static void Main(string[] args)
        {
            Action<string> say = SayHello;
            say("Hello");
        }
        public static void SayHello(string word )
        {
            Console.WriteLine(word);
        }
      static void Main(string[] args)
        {
            Action<string> say = SayHello;
            say("Hello");
        }
        public static void SayHello(string word )
        {
            Console.WriteLine(word);
        }

见栗子

必威 15

必威 16

        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的方法";        }

Action<T1, T2> 委托:两个传入参数,分别为T1T2,没有返回类型。

Action<T1, T2> 委托:两个传入参数,分别为T1T2,没有返回类型。

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

Action同样的还有许多其它重载,每个重载用法一样,只是方法的传入参数数量不一样。

Action同样的还有许多其它重载,每个重载用法一样,只是方法的传入参数数量不一样。

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

其实ActionFunc的用法差不多,差别只是一个有返回类型,一个没有返回类型,当然Action也可以接匿名方法和Lambda表达式。

其实ActionFunc的用法差不多,差别只是一个有返回类型,一个没有返回类型,当然Action也可以接匿名方法和Lambda表达式。

Action

匿名方法:

匿名方法:

Action<T1>

必威 17

必威 18

Action<T1,T2>

    static void Main(string[] args)
        {
            Action<string> say = delegate(string word)
            {
                Console.WriteLine(word);
            };
            say("Hello Word");
        }
    static void Main(string[] args)
        {
            Action<string> say = delegate(string word)
            {
                Console.WriteLine(word);
            };
            say("Hello Word");
        }

Action<T1,T2,T3>

必威 19

必威 20

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

Lambda表达式:

Lambda表达式:

        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作为输入参数,没有返回值的方法");        }
     static void Main(string[] args)
        {
            Action<string> say = s => Console.WriteLine(s);
            say("Hello Word");
        }
     static void Main(string[] args)
        {
            Action<string> say = s => Console.WriteLine(s);
            say("Hello Word");
        }

-----------------------------------------分隔线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的原理了吧。

后记:

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

本文由必威发布于编程,转载请注明出处:【必威】委托到匿名方法到lambda表达式