首页 > 开发 > 综合 > 正文

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

2024-07-21 02:29:14
字体:
来源:转载
供稿:网友
  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

  中间语言结果显示

  双击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 typecount
shirts15
jeans12
shoes 9
pajamas9

  如果你有一个匿名方法(filterby)来通过键和值来过滤字典,按么你可以传递多个参数给lambda表达式来调用这个匿名方法。附带的代码完成了这个filterby的功能:

var clotheslistshortage = clotheslist.filterby((string name, int count)
=> name == "shoes" && count < 10);
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表