zoukankan      html  css  js  c++  java
  • 委托、Lambda表达式

    本文来自:http://wenku.baidu.com/link?url=o9Xacr4tYocCPhivayRQXfIc9kOZeWBwPn2FZfeF19P4-8YX5CMXs74WB-Y8t0S96cb8x7cNpL-2A4OKd3wiet89u0aYszge7pn4U_WfJUq

     1.委托 

    (1)委托的本质 

    委托实际上就是指向函数的指针在C#中委托是一种类型,定义一个委托就是定义一个新的类,它与类的地位是一样的,所以可以定义类的地方都可以定义委托!实际上,使用delegate关键字定义的委托继承了System.MulticastDelegate类,而System.MulticastDelegate类又继承了System.Delegate。

    Delegate:表示委托,委托是一种数据结构,它引用静态方法或引用类实例及该类的实例方法。 

    MulticastDelegate:表示多路广播委托;即,其调用列表中可以拥有多个元素的委托。

     (2)使用委托的示例 

       delegate string DelegateMethod(int a, int b);//定义委托    

       class Program     { 

            static void Main(string[] args)         { 

                DelegateMethod dm = new DelegateMethod(Method);      //或:DelegateMethod dm = Method             

               Console.WriteLine(dm(10, 20));//执行委托             

               Console.Read();         

         } 
            private static string Method(int a, int b)        

         { 
                return "相加结果:" + (a + b);        

          }     


    (3)委托的Invoke与BeginInvoke方法 

    1、Invoke方法 

        实际上,给委托实例提供圆括号(dm(10, 20))与调用委托的Invoke(dm.Invoke(10, 20))方法效果完全相同:     

       delegate string DelegateMethod(int a, int b);//定义委托     

       class Program     

    {  
            static void Main(string[] args)        

           { 
                DelegateMethod dm = Method; 

                Console.WriteLine(dm.Invoke(10, 20));//执行委托             

                Console.Read();         

          } 
            private static string Method(int a, int b)        

        { 
                return "相加结果:" + (a + b);        

        }     


    2、BeginInvoke方法 

         调用委托实例的BeginInvoke方法就是开启一个新的线程执行委托实例指向的方法。     

        delegate void DelegateMethod(int a, int b);//定义委托     

       class Program     

      { 

            static void Main(string[] args)         

          { 
                DelegateMethod dm = Method;            

                for (int i = 0; i < 10; i++)             

               { 
                    dm.BeginInvoke(i, 20, null, null);//异步调用委托             

               } 
                Console.Read();         

         } 
         private static void Method(int a, int b)         

         { 

            Console.WriteLine("相加结果:" + (a + b));  //执行委托         

         }    

    BeginInvoke方法有三种参数:

    第一种参数是委托实例指向的方法的参数(可能有多个);

    第二种参数的类型是AsyncCallback,AsyncCallback是一个委托类型,其定义是delegate void AsyncCallback(IAsyncResult ar),当调用BeginInvoke方法的委托实例异步执行完成时,

    就会执行该参数指向的方法;

    第三种参数是object类型,主要是向第二种参数传递一些值,一般可以传递被调用方法的委托,这个值可以使用IAsyncResult.AsyncState属性获得。(具体请参考“C#多线程”)     

    delegate void DelegateMethod(int a, int b);//定义委托     

    class Program     

            static void Main(string[] args)         

            { 
                DelegateMethod dm = Method; 
                dm.BeginInvoke(10, 20, MethodCompleted, null);//异步调用委托            

                Console.Read();         

            } 
            //异步委托 
            private static void Method(int a, int b)         

           { 
                Console.WriteLine("相加结果:" + (a + b));             

                Thread.Sleep(3000);         

           } 
            //回调函数 
            private static void MethodCompleted(IAsyncResult ar)         

            { 
                Console.WriteLine("休眠结束!");      

            }     


    3、委托的EndInvoke方法 

    如果调用了委托实例的BeginInvoke方法,就可以通过EndInvoke方法获得委托实例指向的方法的返回值,或是确定指向的方法已经被成功调用。(具体请参考“C#多线程”)    

     delegate string DelegateMethod(int a, int b);//定义委托     

    class Program     


            static void Main(string[] args)         

           { 
                DelegateMethod dm = Method; 

                IAsyncResult ar = dm.BeginInvoke(10, 20, null, null);//异步调用委托             

               string result = dm.EndInvoke(ar);//等待委托异步调用结束             

               Console.WriteLine(result);//输出返回值            

              Console.Read();         

           } 
            //异步委托 
            private static string Method(int a, int b)        

            { 
                Thread.Sleep(3000); 
                return "相加结果:" + (a + b);         

            }     


    (4)Action<T>、Func<T>与Predicate<T>(泛型委托) 

    除了为每个参数和返回类型定义一个新委托之外,还可以使用Action<T>与Func<T>泛型委托。使用泛型委托主要的优势是可以省略委托的定义。 

    1、Action<T>无返回值的泛型委托 

    泛型Action<T>委托表示引用一个void返回类型的方法,这个委托类可以有多个(≥0)参数且参数的类型可以不同(最多可以有16种不同类型的参数)。     

    class Program     

            static void Main(string[] args)        

            { 
                Action<int,int> dm = Method;//委托实例             

                dm(10,20);//调用委托            

                Console.Read();        

             } 
            private static void Method(int a, int b)          

            { 
                Console.WriteLine("相加结果:" + (a + b));        

            }     


    2、Func<T>带有返回值的泛型委托 
    泛型Func<T>委托与Action<T>委托类似,不同点是Func<T>允许调用带返回值类型的方法,而且其返回值类型的指定是Func<T1,T2,T3...Tn>中的最后一个类型(Tn),即Tn就是其返回值,其它类型都表示参数的类型。(最多可以有16种参数类型和一个返回值类型)     

    class Program     


            static void Main(string[] args)         

           { 
                Func<int, int, string> dm = Method;//委托实例             

                string result = dm(10, 20);//调用委托             

                Console.WriteLine(result);//输出返回值             

                Console.Read();         

            } 
            private static string Method(int a, int b)         

           { 
                return "相加结果:" + (a + b);         

           }     


    3、Predicate<T>委托(常用于集合参数,Array 和 List ) 
    Predicate<T>泛型委托,只能接受一个传入参数,返回值为bool类型。    

     class Program     


            static void Main(string[] args)         

            { 
                 Predicate<int> dm = Method;//委托实例            

                 if (dm(12))//调用委托            

                { 
                    Console.WriteLine("偶数");             

                }            

               else           

               { 
                    Console.WriteLine("奇数");             

                } 
                Console.Read();         

            } 
            private static bool Method(int a)        

            { 
                 if(a%2==0)             

                 { 
                    return true;            

                 } 
                   return false;         

            }     

    其他使用到Predicate 有

    Array.Find , Array.FindAll , Array.Exists , Array.FindLast , Array.FindIndex ..... 
      List<T>.Find , List<T>.FindAll , List<T>.Exists , List<T>.FindLast , List<T>.FindIndex ..... 
    延伸:
      除了上面提到的外,你完全可以使用Predicate 定义新的方法,来加强自己代码。

    复制代码
    public class GenericDelegateDemo
    {
        List<String> listString = new List<String>()
        {
            "One","Two","Three","Four","Fice","Six","Seven","Eight","Nine","Ten"
        };

        public String GetStringList(Predicate<String> p)
        {
            foreach(string item in listString)
            {
                if (p(item))
                    return item;
            }
            return null;
        }

        public bool ExistString()
        {
            string str = GetStringList((c) => { return c.Length <= 3 && c.Contains('S'); });
            if (str == null)
                return false;
            else
                return true;
        }
    }


    (5)多播委托 
    前面的委托只包含一个方法,但是委托也可以包含多个方法,这种委托称为多播委托。如果调用多播委托就可以按顺序连续调用多个方法,为此委托的定义就必须返回void,否

    则就只能得到委托调用的最后一个方法的结果。多播委托可以识别“+、-、+=、-=”运算符。 
        class Program     

            static void Main(string[] args)         

            { 
                Action<int> dm = null; //委托实例             

                for (int i = 0; i < 20; i++)            

                { 
                    if (i % 2 == 0)                

                { 
                        dm += Method1;                

                 }                 

               else                

              { 
                        dm += Method2;                 

               }             

         } 
                dm(123456);//调用多播委托             

               Console.Read();       

      } 
            private static void Method1(int a)         

           { 
                Console.WriteLine("委托1:" + a);         

             } 
            private static void Method2(int a)        

           { 
                Console.WriteLine("委托2:" + a);       

          }    

     } 
    (6)使用委托定义匿名方法 
       
     class Program    

     { 
            static void Main(string[] args)         

           { 
                Action<int> dm = delegate(int a)

                    Console.WriteLine(a.ToString());             

              };//匿名方法 

                dm(123456);//调用委托指向的匿名方法             

              Console.Read();         

         }    

     } 
    2.Lambda表达式 


    (1)Lambda表达式本质  

    Lambda表达式的本质是一个匿名函数,Lambda表达式只能与委托配合使用,其优势在可以很方便的定义匿名方法。所有Lambda表达式都使用Lambda运算符=>,该运算符读

    作"goes to"。Lambda运算符的左边是输入参数(如果有),右边是表达式或语句块。

     (2)Lambda表达式使用示例 

        class Program    

     { 
            static void Main(string[] args)         

            { 
                //标准的Lambda格式 
                Func<int, int, string> sum0 = (int a, int b) => { return "和是:" + (a + b); };             

                Console.WriteLine(sum0(10, 20));             //简写格式 

                Func<int, int, string> sum1 = (a, b) => "和是:" + (a + b);             

               Console.WriteLine(sum1(30, 40)); 

               Action<int, int> sum2 = (a, b) => Console.WriteLine("和是:" + (a + b));             

               sum2(50, 60);             

               Console.Read();         

            }     


    (3)Lambda表达式语法 


    1、表达式Lambda语法(参数语法) 


    如果只有一个输入参数时,括号可以省略,如:(x) => x * x 等于 x => x * x 

    如果具有一个以上的输入参数,必需加上括号,如:(x, y) => x == y 可以显式指定输入参数的类型,如:(int x, string s) => s.Length > x 

    也可以没有任何输入参数,如:() => Console.WriteLine("无参数的Lambda表达式") 


    2、语句Lambda语法(函数体语法) 

    语句写在大括号中,如: 

    Action<int, int> sum = (a, b) => { int i = a = +b; Console.Write(i); }; 只有一条语句时,可以省略大括号“{}”,如: 


    Action<int, int> sum = (a, b) => Console.Write(a + b); 当匿名方法有返回值时,可以使用return,如: 


    Func<int, int, string> sum0 = (a, b) => { return "和是:" + (a + b); }; 当匿名方法有返回值,且只有一条语句时,可以省略大括号“{}”和return,如: 


    Func<int, int, string> sum1 = (a, b) => "和是:" + (a + b); 


    注意:当有返回值时,语句Lambda中使用了大括号就一定要使用return关键字返回;反之使用了return关键字返回结果就一定要使用大括号。即:return关键字与大括号必须同时省略!

     
    3、类型猜测 

    当编写一个Lambda式的时候,我们通常不需要明确指定输入参数的类型。因为编译器会根据Lambda体的实现,以及委托的定义来猜测类型。如:如果要从一个List<int>中删除小于100的元

    素 

    List<int> list = new List<int>();  


    list.RemoveAll(i => i < 100);//i会被猜测为int 通常的猜测规则如下: 


    Lambda式必须包含与委托定义中相等数量的输入参数; 


    每个Lambda式的输入参数必须能够隐式转换成委托定义中所要求的输入参数; Lambda式的返回值必须能够隐式转换成委托定义中的返回值。 


    4、Lambda式中的变量作用域 


    在Lambda式定义中可以引用外部变量。只要是在定义处能够访问到的变量,都可以在Lambda式中引用。所有会被引用的外部变量必须在Lambda式定义之前被显式赋值。 


    变量作用域的规则: 


    1)、被“捕获”的变量在委托的生命周期结束前都不会被垃圾回收; 

    2)、在Lambda式内部定义的变量对外不可见; 

    3)、Lambda式无法直接捕获一个具有ref或out描述的参数变量; 

    4)、Lambda式中的return语句不会导致当前所在的方法返回; 

    5)、Lambda式中不允许包含会导致跳当前执行范围的goto,break 或 continue语句。

  • 相关阅读:
    基本排序算法分析
    Linux内核浅谈
    Linux内核浅谈
    Linux内核浅谈
    淘宝架构技术的演变
    淘宝架构技术的演变
    淘宝架构技术的演变
    中间件小结
    中间件小结
    中间件小结
  • 原文地址:https://www.cnblogs.com/zhouyunbaosujina/p/4065059.html
Copyright © 2011-2022 走看看