技术开发 频道

C# 3.0新特性体验之Lambda表达式

【IT168 技术文档】

  C#2.0介绍了一个新特性--匿名方法,允许开发者在线(inline)声明自己的函数代码而无须使用委托函数(delegate function)。C#3.0中提供了一个新特性--Lambda表达式,它提供了完成相同目标的更加简洁的格式。让我们在讨论Lambda表达式以前仔细研究一下匿名方法。
 
匿名方法

  假设你需要创建一个按钮,当点击它的时候更新ListBox里的内容。在C#1.0和1.1里,你要这样做:

public MyForm() {  listBox = new ListBox(...);  textBox = new TextBox(...);  addButton = new Button(...);  addButton.Click += new EventHandler(AddClick); } void AddClick(object sender, EventArgs e) {  listBox.Items.Add(textBox.Text); }
  在C#2.0里,你需要这样做:
public MyForm() {  listBox = new ListBox(...);  textBox = new TextBox(...);  addButton = new Button(...);  addButton.Click += delegate  {   listBox.Items.Add(textBox.Text); };
  就像你看到的一样,你不必要特别的声明一个新方法来将它连接到一个事件上。你可以在C#2.0里使用匿名方法来完成同样的工作。C#3.0里介绍了一种更加简单的格式,Lambda表达式,你可以直接使用"=>"来书写你的表达式列表,后面跟上一个表达式或者语句块。
 
Lambda表达式中的参数
 
  Lambda表达式中的参数可以是显式或者隐式类型的。在一个显式类型参数列表里,每个表达式的类型是显式指定的。在一个隐式类型参数列表里,类型是通过上下文推断出来的:
 
(int x) => x + 1 // 显式类型参数
(y,z) => return y * z; // 隐式类型参数
 
Lambda演算实例
 
  下面的例子给出了两种不同的方法来打印出一个list中长度为偶数的字符串。第一种方法AnonMethod使用了匿名方法,第二种LambdaExample则是通过Lambda演算实现:
// Program.cs using System; using System.Collections.Generic; using System.Text; using System.Query; using System.XML.XLinq; using System.Data.DLinq; namespace LambdaExample {  public delegate bool KeyValueFilter<K, V>(K key, V value);  static class Program  {   static void Main(string[] args)   {    List<string> list = new List<string>();    list.Add("AA");    list.Add("ABC");    list.Add("DEFG");    list.Add("XYZ");    Console.WriteLine("Through Anonymous method");    AnonMethod(list);    Console.WriteLine("Through Lambda expression");    LambdaExample(list);    Dictionary<string, int> varClothes= new Dictionary<string,int>();    varClothes.Add("Jeans", 20);    varClothes.Add("Shirts", 15);    varClothes.Add("Pajamas", 9);    varClothes.Add("Shoes", 9);    var ClothesListShortage = varClothes.FilterBy((string name,    int count) => name == "Shoes" && count < 10);    // example of multiple parameters    if(ClothesListShortage.Count > 0)     Console.WriteLine("We are short of shoes");    Console.ReadLine();  }  static void AnonMethod(List<string> list)  {   List<string> evenNumbers = list.FindAll(delegate(string i)   { return (i.Length % 2) == 0; });   foreach (string evenNumber in evenNumbers)   {    Console.WriteLine(evenNumber);   }  }  static void LambdaExample(List<string> list)  {   var evenNumbers = list.FindAll(i =>(i.Length % 2) == 0); // example of single parameter   foreach(string i in evenNumbers)   {    Console.WriteLine(i);   }  } } public static class Extensions {  public static Dictionary<K, V> FilterBy<K, V> (this Dictionary<K, V> items, KeyValueFilter<K, V> filter)  {   var result = new Dictionary<K, V>();   foreach(KeyValuePair<K, V> element in items)   {    if (filter(element.Key, element.Value))     result.Add(element.Key, element.Value);   }   return result;  }   } }

 

  如果你安装了Visual Studio 2005 and LinQ Preview,你可以使用编辑器来编译程序。如果没有的话,可以使用命令行方式:
C:\Program Files\LINQ Preview\Bin\Csc.exe /reference:"C:\Program Files\LINQ Preview\Bin\System.Data.DLinq.dll" /reference:C:\Windows\Microsoft.net\Framework\v2.0.50727\System.Data.dll /reference:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.dll /reference:"C:\Program Files\LINQ Preview\Bin\System.Query.dll" /reference:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.XML.dll /reference:"C:\Program Files\LINQ Preview\Bin\System.Xml.XLinq.dll" /target:exe Program.cs
中间语言结果显示
 
  打开ILDASM,双击AnonMethod函数你将看到C#编译器产生的中间语言代码:
.method private hidebysig static void AnonMethod(class [mscorlib]System.Collections.Generic.List`1<string> list) cil managed {  // Code size 96 (0x60)  .maxstack 4  .locals init ([0] class [mscorlib]System.Collections.Generic.List  `1<string> evenNumbers,  [1] string evenNumber,  [2] valuetype [mscorlib]System.Collections.Generic.List  `1/Enumerator<string> CSCODE_REPLACEMENT 000,  [3] bool CSCODE_REPLACEMENT 001)  IL_0000: nop  IL_0001: ldarg.0  IL_0002: ldsfld class [mscorlib]System.Predicate  `1<string> LambdaExample.Program::  `<>9__CachedAnonymousMethodDelegate1'  IL_0007: brtrue.s IL_001c  IL_0009: ldnull  IL_000a: ldftn bool LambdaExample.Program::  `<AnonMethod>b__0'(string)  IL_0010: newobj instance void class [mscorlib]System.Predicate  `1<string>::.ctor(object, native int)  IL_0015: stsfld class [mscorlib]System.Predicate`1<string>  LambdaExample.Program::  `<>9__CachedAnonymousMethodDelegate1'  IL_001a: br.s IL_001c  IL_001c: ldsfld class [mscorlib]System.Predicate`1<string>  LambdaExample.Program::'<>  9__CachedAnonymousMethodDelegate1'  IL_0021: callvirt instance class [mscorlib]System.Collections.  Generic.List`1<!0> class [mscorlib]System.  Collections.Generic.List`1<string>::  FindAll(class [mscorlib]System.Predicate`1<!0>)  IL_0026: stloc.0  IL_0027: nop  IL_0028: ldloc.0  IL_0029: callvirt instance valuetype [mscorlib]System.Collections.  Generic.List`1/Enumerator<!0> class  [mscorlib]System.Collections.Generic.List`1  <string>::GetEnumerator()  IL_002e: stloc.2  .try  {   IL_002f: br.s IL_0042   IL_0031: ldloca.s CSCODE_REPLACEMENT 000   IL_0033: call instance !0 valuetype [mscorlib]System.   Collections.Generic.List`1/Enumerator   <string>::get_Current()   IL_0038: stloc.1   IL_0039: nop   IL_003a: ldloc.1   IL_003b: call void [mscorlib]System.Console::   WriteLine(string)   IL_0040: nop   IL_0041: nop   IL_0042: ldloca.s CSCODE_REPLACEMENT 000   IL_0044: call instance bool valuetype [mscorlib]System.   Collections.Generic.List`1/Enumerator   <string>::MoveNext()   IL_0049: stloc.3   IL_004a: ldloc.3   IL_004b: brtrue.s IL_0031   IL_004d: leave.s IL_005e  } // end .try  finally  {   IL_004f: ldloca.s CSCODE_REPLACEMENT 000   IL_0051: constrained. valuetype [mscorlib]System.Collections.   Generic.List`1/Enumerator<string>   IL_0057: callvirt instance void [mscorlib]System.   IDisposable::Dispose()   IL_005c: nop   IL_005d: endfinally  } // end handler  IL_005e: nop  IL_005f: ret } // end of method Program::AnonMethod
  这里我们可以看到,实际上匿名方法和lambda表达式生成了相同的中间代码,并且他们的执行也是类似的。
 
多参数的Lambda表达式
 
  Lambda表达式可以带上多个参数,比如你可以声明一个Dictionary类型:
 
Clothing Type  Count
Shirts      15
Jeans      12
Shoes      9
Pajamas     9
 
  如果你有一个匿名方法(FilterBy)来通过键和值来过滤字典,按么你可以传递多个参数给lambda表达式来调用这个匿名方法。附带的代码完成了这个FilterBy的功能:
var ClothesListShortage = clothesList.FilterBy((string name, int count) => name == "Shoes" && count < 10);
0
相关文章