lamada 表达式

  linq的基本功能是创建操作管道,以及这些操作需要的任何状态,这些操作表示了各种关于数据的
逻辑,如何刷选,如何排序以及如何将不同的数据源联接到一起,当linq查询在"进程内"执行的时候
那些操作通常用委托来表示:

   使用linq to object来处理数据的时,经常会出现一个语句包含几个委托的情况,C sharp3 的lambda表达

式在不牺牲可读性的前提下使这一切成为可能,

 

简而言之:: lamada 表达式 是对linq数据管线中的操作进行表示的一种符合语言习惯的方式:


1:作为委托的lambda表达式:
      从许多方面: lamada 表达式都可以看作事实C  sharp2的匿名方法的一种演变  ,匿名方法能做的几乎
一切事情都可以用lamada 表达式来完成:

 

  特别是: 捕获的变量在lambda表达式的行为和匿名方法是一样的,从显示的形式来看,两者并不大的区别,

只是lamada 表达式支持许多快捷语法,使它们更易读,更简练:


     与匿名方法相似.lamada 表达式有特殊的转换规则,表达式类型的本身并非委托类型,
但它可以通过多种方式隐式或显式地转换一个委托实例:

匿名函数这个术语同时涵盖了匿名方法和lambda表达式---在很多情况下,两者可以使用相同的转换规则:

 

  Func returnLength;
            returnLength = delegate(string text) { return text.Length; };

            Console.WriteLine(returnLength("Hello"));

匿名方法是: delegate(string text) { return text.Length; };


也是打算转换成lamabda表达式的部分:

  lamada 表达式最冗长的形式是:
    (显式类型参数列表) => {语句};   //  => 这个东东用来告诉编译器:  我们正在使用一个lambda表达式


 Func returnLength;
            returnLength = (string text) => { return text.Length; };


大多数的时候:  可以用一个表达式来表示整个主体,该表达式的值是lamabda的结果:
   格式即将变成:
   (显式类型的参数列表 => 表达式 )
   (string  text=>text.length

 

隐式类型的参数列表
  (隐式类型的参数列表) =>表达式:
 
  隐式类型的参数列表就是一个以逗号分隔的名称列表,没有类型,但显式类型和隐式类型的
参数不能混合使用----要么整个列表都是显式类型的,要么全部是隐式类型.除此之外如果有
任何out参数或 ref参数,就只能使用显式类型:
    可以继续写成:
 
 (text)=>text.length:

单一参数的快捷语法:
   如果 lamada 表达式只需一个参数,而且哪个参数可以隐式(指定)类型,C  sharp3就允许省略圆括号:

这种格式的 lamada 表达式是:
    参数名 => 表达式
  text=>text.length:
 


//*****:   使用list事件简单的例子:
        对列表进行刷选,排序并设置其他操作:

     < list>的findall的方法,它获取一个predicate,并返回一个新列表,新列表中包含原始列表中与
谓语匹配的所有的元素:
   sort方法获取一个comparision,并相应地对列表进行排序,最后一个获取:foreach方法获取一个Action
 ,对每个元素执行设置的行为:

      class FilmFilteringAndSorting
    {
        class Film
        {
            public string Name { get; set; }
            public int Year { get; set; }
        }
        static void Main()
        {
            var films = new List
            {
                new Film {Name="Jaws", Year=1975},
                new Film {Name="Singing in the Rain", Year=1952},
                new Film {Name="Some like it Hot", Year=1959},
                new Film {Name="The Wizard of Oz", Year=1939},
                new Film {Name="It's a Wonderful Life", Year=1946},
                new Film {Name="American Beauty", Year=1999},
                new Film {Name="High Fidelity", Year=2000},
                new Film {Name="The Usual Suspects", Year=1995}
            };
            #region--Action行为

            //             < list>的findall的方法,它获取一个predicate,并返回一个新列表,新列表中包含原始列表中与
//谓语匹配的所有的元素:
//   sort方法获取一个comparision,并相应地对列表进行排序,最后一个获取:foreach方法获取一个Action
// ,对每个元素执行设置的行为:
            //lamabda表达式  
            //Action print =
            //    film => Console.WriteLine("Name={0}, Year={1}", film.Name, film.Year);

               //用委托表达式
            Action print = delegate(Film film)  //表示方法:   Action对T的某个实例做某事
            {
                Console.WriteLine("Name={0}, Year={1}", film.Name, film.Year);
            };

            //Action print =
            //    film => Console.WriteLine("Name={0}, Year={1}", film.Name, film.Year);
             //Note: extra lines added for clarity when running
            Console.WriteLine("All films");
            films.ForEach(print);                               
            Console.WriteLine();
            #endregion
            Console.WriteLine("Oldies");
            films.FindAll(film => film.Year < 1960)
                 .ForEach(print);
            Console.WriteLine();
            //用C#2.0委托表达式
            Predicate filter = delegate(Film film)   //查找符合的条件
            {
                return film.Year < 1960;
            };
            Console.WriteLine("OldiesC#2.0的委托表达方式");
            films.FindAll(filter).ForEach(print);
            Console.WriteLine();


            Console.WriteLine("Sorted");
            films.Sort((f1, f2) => f1.Name.CompareTo(f2.Name));
            films.ForEach(print);

            Console.WriteLine("SortedC#2.0的委托表达方式");
            Comparison compare = delegate(Film f1, Film f2)
            {
                return f1.Name.CompareTo(f2.Name);
            };
            films.Sort(compare);
            films.ForEach(print);              
        }       
    }


  // 记录事件的本质,又记录与它的发送者和实参有关的信息,也就是你熟悉的delegate(object  sender ,EventArgs e){...}
        static void Log(string title, object sender, EventArgs e)
        {
            Console.WriteLine("Event: {0}", title);
            Console.WriteLine("  Sender: {0}", sender);
            Console.WriteLine("  Arguments: {0}", e.GetType());
            foreach (PropertyDescriptor prop in
                     TypeDescriptor.GetProperties(e))  // PropertyDescriptor属性描述符
            {
                string name = prop.DisplayName;
                object value = prop.GetValue(e);
                Console.WriteLine("    {0}={1}", name, value);
            }
        }

        static void Main()
        {
            Button button = new Button();
            button.Text = "Click me";
            button.Click += (src, e) => Log("Click", src, e);
            button.KeyPress += (src, e) => Log("KeyPress", src, e);
            button.MouseClick += (src, e) => Log("MouseClick", src, e);

            Form form = new Form();
            form.AutoSize = true;
            form.Controls.Add(button);
            Application.Run(form);
        }


表达式树:

      .net3.5的表达式树提供了一种抽象的方式将一些代码表示成一个对象树,只适用于表达式,表达式树主要在
 linq中使用:

     C#3对于将lamabda表达式转化成表达式树提供了内建的支持,但在讨论这个问题之前,首先
应理解在没有使用任何编译器技术的情况下,它们是如何与.net  framwork 融合为一体的:


      

 

///
  // 一个非常简单的表达式的树
    class FirstExpressionTree
    {
        static void Main()
        {
            Expression firstArg = Expression.Constant(2);
            Expression secondArg = Expression.Constant(3);
            Expression add = Expression.Add(firstArg, secondArg);

            Console.WriteLine(add);
        }
    }


//编译并执行一个表达树:

        //    Expression 与LambdaExpression类的区别在于,泛型类以静态类型的方式标识了它是
        //  什么种类的表达式,也就是说她确定了返回类型和参数,很明显,这用是TDelegate类型参数来表示的,它必须
        // 是一个委托类型  ,
        static void Main()
        {
            Expression firstArg = Expression.Constant(2);
            Expression secondArg = Expression.Constant(3);
            Expression add = Expression.Add(firstArg, secondArg);

            //   Func不获取任何参数,返回一个整数的委托
            Func compiled = Expression.Lambda>(add).Compile();
            Console.WriteLine(compiled());
        }


  //首先表达式树只能表示单一的表达式,她们不能表示完整的类,方法甚至语句,其次,C#通过lamabda表达式直接在语言中支持表达式树:


   // 用lambda表达式创建表达式树:
    //注意,并不是所有的lambda表达式可以转换成表达式树
    class LambdaExpressionToExpressionTree
    {
        static void Main()
        {
            Expression> return5 = () => 5; //() => 5是lambda表达式
            Func compiled = return5.Compile();
            Console.WriteLine(compiled());
        }
    }

 

    //较为复杂的表达式树:
    class LambdaExpressionWithParametersToExpressionTree
    {
        static void Main()
        {
            Expression> expression = (x, y) => x.StartsWith(y);

            var compiled = expression.Compile();

            Console.WriteLine(compiled("First", "Second"));
            Console.WriteLine(compiled("First", "Fir"));
        }
    }

 

  //较为复杂的表达式树:
    class LambdaExpressionWithParametersToExpressionTree
    {
        static void Main()
        {
            Expression> expression = (x, y) => x.StartsWith(y);

            var compiled = expression.Compile();

            Console.WriteLine(compiled("First", "Second"));
            Console.WriteLine(compiled("First", "Fir"));
        }
    }

 


    //用代码构造一个方法调用表达式树:
       //C虽然C#3编译器在编译好的代码中会使用与代码清单9-10相似的代码来构造表达式树
    class MethodCallExpressionTree
    {
        static void Main()
        {
            MethodInfo method = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
            var target = Expression.Parameter(typeof(string), "x");
            var methodArg = Expression.Parameter(typeof(string), "y");
            Expression[] methodArgs = new[] { methodArg };
            //  以上代码:构造方法调用一个表达式树:

            Expression call = Expression.Call(target, method, methodArgs); //以上部件创建调用表达式call

            var lambdaParameters = new[] { target, methodArg };
            var lambda = Expression.Lambda>(call, lambdaParameters);

            var compiled = lambda.Compile();  //将call转换成lambda表达式

            Console.WriteLine(compiled("First", "Second"));
            Console.WriteLine(compiled("First", "Fir"));
        }
    }

 

 //  总结lamada表达式提供了编译时检查的能力,而表达树将执行模型从你所需的逻辑中提取出来:


    //  linq   to  object 和linq  to sql

    //  linq   to  object是含有lamada表达式的C#查询代码-->C#编译器-->使用 委托的IL--->委托直接在CLR执行--->查询结果
    // linq  to sql  是含有lamada表达式的C#查询代码-->C#编译器-->使用表达树的IL--->LINQ TO  SQL provider-->动态SQL--->在数据库处执行并取回结果----查询结果:

      //----类型推断与重载决策发生的改变:以下代码C3#能通过,而C#不行的:
        //C#2的类型推断规则是单独针对每一个实参来进行的,没有办法将从一个实参推断出来的类型直接用于另一个实参:
    class ConversionWithTypeInference
    {
        static void PrintConvertedValue
            (TInput input, Converter converter)
        {
            Console.WriteLine(converter(input));
        }
       
        static void Main()
        {
            PrintConvertedValue("I'm a string", x => x.Length);
        }
    }

 

// 展示了貌似能编译,但不符合C#2类型判断规则的一些示例代码
    class ReturnTypeInference
    {
        delegate T MyFunc();//声明了.net2.0中没有的FUNC(T);

        static void WriteResult(MyFunc function)
        {
            Console.WriteLine(function());
        }

        static void Main()
        {
            WriteResult(delegate { return 5; }); // // C#3比起C#2的巨大改变:所有方法的实参在C#3中是以"团队"的形式来工作的:
            //两个解决的办法:
             //a:要么显式指定类型的实参(就象编译器推荐的那样)
            WriteResult(delegate { return 5; });
            //  将匿名方法强制转换为一个具体的委托类型:
            WriteResult((MyFunc)delegate { return 5; });
            
        }


 class OverloadingByDelegateReturnType
    {
        static void Execute(Func action)
        {
            Console.WriteLine("action returns an int: " + action());
        }

        static void Execute(Func action)
        {
            Console.WriteLine("action returns a double: " + action());
        }

        static void Main()
        {
            Execute(() => 1); //用委托lamada表达式转换成func或f
            //在C#2中是会有错误的:
            //但在C#3中最终会选中参数为func的方法:额外的添加的规则:
            // 如果一个匿名函数能转换成参数列表相同,但返回类型不同的两个委托类型,就根据从
            //"推断的返回类型"到"委托的返回类型"的转换来判定那个委托转换"更好"
        }
    }
    }

}

你可能感兴趣的:(C#3ndepth,linq,string,lambda,c#,编译器,class)