VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Objective-C编程 >
  • c#3.0入门第一章 Lambda表达式第四节Lambda的用途&类型声明能够和不能够省略的地

制作者:剑锋冷月 单位:无忧统计网,www.51stat.net  成问题的是,虽然为了源代码的简洁性,很想用Lambda表达式,但是要写的代码却不能全部都用Lambda表达式来写。
 
  那么, Lambda表达式究竟能做到什么程度呢?
 
  习惯了C/C++编程风格的程序员,一定以为因C#语法与之很相似,所以用C#编写相对复杂的程序应该也没有问题。可是很遗憾,情况不是这样。那是因为C/C++具有能写出复杂功能的表达式的逗号表达式,而C#却没有。
 
  例如,C/C++中,下面的代码是可行的。
 
int a,b,c;
 
c = (a=1, b=2, a+b); // a=1、b=2、c=a + b
printf("%d\n",c);
 
  正因为仅仅一个表达式就能做相当多的处理,所有逗号表达式才有着重要的意义。
 
  但是,C#却没有这样的用法。
 
  但是C#有三元运算符?:和空接合运算符??。通过使用这些运算符,相当数量的代码都可以用Lambda表达式来写了。
 
  例如,“根据参数指定的文件名向文件中写入字符串,参数为null的情况下,用‘default.txt’作为默认文件名”这样的Lambda表达式,像下面那样,用空接合运算符??就可以用Lambda表达式来写。
 
using System;
 
class Program
{
  static void Main(string[] args)
  {
    Action<string> method =
      (filename) => System.IO File.WriteAllText(
                          filename ?? "default.txt", "Hello!");
 
    method(null); // 生成default.txt 
    method("hello.txt"); // 生成hello.txt
  }
}
 
  List11 使用了空接合运算符??的Lambda表达式
 
  或者“参数的flag如果是false的话,文件名就是‘normal.log’,true的话就是‘system.log’”的情况下,使用三元运算符(?:)按照如下的方式以表达式形式的Lambda来写。
 
编缉推荐阅读以下文章
 
[C# 3.0 入门] [第一章 Lambda表达式] 第五节:Lambda表达式的使用范例 & Lambda表达式的各种变体 
[C# 3.0 入门] [第一章 Lambda表达式] 第三节:Lambda与匿名方法的区别 
[C# 3.0 入门] [第一章 Lambda表达式] 第二节:Lambda表达式带来了什么 
[C# 3.0 入门] [第一章 Lambda表达式] 第一节:C# 3.0 是什么 & C# 3.0的适用范围 
C# 3.0 入门系列(一) 
using System;
 
class Program
{
  static void Main(string[] args)
  {
    Action<bool> method =
      (system) => System.IO.File.AppendAllText(
          system ? "system.log" : "normal.log", "log message\r\n");
 
    method(false); // 生成normal.log 
    method(true); // 生成system.log 
  }
}
 
  List12 使用三元运算符(?:)的Lambda表达式
 
  但是,前一章的List10的例子里,其中的if语句中就不能改用三元运算符来替换。如果试图替换的话就是以下情况:
 
using System;
 
class Program
{
  static void Main(string[] args)
  {
    Action<string> method = (filename) =>
      filename == null
        ? Console.WriteLine("Hello!")
        : System.IO.File.WriteAllText(filename, "Hello!");
 
    method(null);
    method("hello.txt");
  }
}
 
  List13 List10中用三元运算符改写后(产生编译错误)
 
  这个代码,会产生以下的编译错误:
 
  error CS0201: 只有 assignment、call、increment、decrement 和 new 对象表达式可用作语句。
 
  error CS0173: 无法确定条件表达式的类型,因为“void”和“void”之间没有隐式转换。
 
  这并不是说Lambda表达式不能调用具有void返回值的方法。下面的代码就没有问题。
 
Action<string> method =
  (filename) => System.IO.File.WriteAllText(filename, "Hello!");
 
编缉推荐阅读以下文章
 
[C# 3.0 入门] [第一章 Lambda表达式] 第五节:Lambda表达式的使用范例 & Lambda表达式的各种变体 
[C# 3.0 入门] [第一章 Lambda表达式] 第三节:Lambda与匿名方法的区别 
[C# 3.0 入门] [第一章 Lambda表达式] 第二节:Lambda表达式带来了什么 
[C# 3.0 入门] [第一章 Lambda表达式] 第一节:C# 3.0 是什么 & C# 3.0的适用范围 
C# 3.0 入门系列(一) 
  这里产生error的原因是,三元运算符的第二个、第三个运算数不能写成void类型的表达式(因为这样写,void没法隐式转换成第二个、第三个运算数的类型,所以整个表达式的类型就无法判断了。
 
  因为存在这样的问题,有void类型的返回值的表达式情况下,三元运算符使用就很困难。其实,void返回值的表达式很难理解,不能写反而是个好事。
 
  除了void型以外,其它类型的表达式,使用三元运算符就没有问题。下面的代码在编译和执行时就没有问题。
 
 1using System;
 2
 3class Program
 4{
 5  static void Main(string[] args)
 6  {
 7    Func<int, bool> method = (year) =>
 8      year < 1994 ? year % 4 == 0 : year % 4 == 2;
 9
10    Console.WriteLine("冬奥会年份");
11    for (int i = 1988; i < 1999; i++)
12    {
13      Console.WriteLine("{0}年={1}", i, method(i));
14    }
15    // 输出:
16    // 冬奥会年份
17    // 1988年=True
18    // 1989年=False
19    // 1990年=False
20    // 1991年=False
21    // 1992年=True
22    // 1993年=False
23    // 1994年=True
24    // 1995年=False
25    // 1996年=False
26    // 1997年=False
27    // 1998年=True
28  }
29}
30
 
  List14 使用三元运算符的Lambda表达式
 
  代入变量method的Lambda表达式,判断参数的年份是不是冬奥会举行的年份,1994年以后,因为是两年举行一届,所以判断方式也要改变。这种情况下,当然是三元运算符派上用场的时候。总之,这种程度的问题,用表达式形式的Lambda就比较容易写。
 
编缉推荐阅读以下文章
 
[C# 3.0 入门] [第一章 Lambda表达式] 第五节:Lambda表达式的使用范例 & Lambda表达式的各种变体 
[C# 3.0 入门] [第一章 Lambda表达式] 第三节:Lambda与匿名方法的区别 
[C# 3.0 入门] [第一章 Lambda表达式] 第二节:Lambda表达式带来了什么 
[C# 3.0 入门] [第一章 Lambda表达式] 第一节:C# 3.0 是什么 & C# 3.0的适用范围 
C# 3.0 入门系列(一) 
  不用类型声明的情况和必须类型声明的情况
 
  大部分情况下,Lambda表达式的参数类型都可以省略。然而,Lambda表达式的使用也存在限制,不能推定出类型的情况下就不能用Lambda表达式。
 
  例如,Lambda表达式就不能代入到使用var关键字隐式类型声明的局部变量:
 
  var Lambda = (int x) =>x *2;
 
  上面的代码会产生“Lambda表达式局部变量隐式的类型声明不会起作用”的错误。避免错误的方法是不要用var,而是明确的进行类型声明。
 
  然而,
 
  下面的例子
 
 1using System;
 2
 3delegate int delegate1( int x );
 4delegate int delegate2( string s );
 5
 6class Program
 7{
 8  private static void sample(delegate1 method)
 9  {
10    Console.WriteLine("void Sample(delegate1 method)");
11  }
12
13  private static void sample(delegate2 method)
14  {
15    Console.WriteLine("void Sample(delegate2 method)");
16  }
17
18  static void Main(string[] args)
19  {
20    sample((int x) => 0);
21    // sample((x) => 0); // 如果没有参数类型声明会产生错误
22  }
23}
24
 
  List 15 必须指定参数类型的情况
 
  这个例子中,“sample((x)=> 0”会产生编译错误。满足条件的sample方法有两个,所有就不能确定究竟应该使用哪个。然而,在参数前加上类型声明“sample((int x) => 0”,就能够编译执行。因为参数类型的指定,在2个sample方法中,有一个与之类型相吻合,所以以此为依据就能够选择了。
 
编缉推荐阅读以下文章
 
[C# 3.0 入门] [第一章 Lambda表达式] 第五节:Lambda表达式的使用范例 & Lambda表达式的各种变体 
[C# 3.0 入门] [第一章 Lambda表达式] 第三节:Lambda与匿名方法的区别 
[C# 3.0 入门] [第一章 Lambda表达式] 第二节:Lambda表达式带来了什么 
[C# 3.0 入门] [第一章 Lambda表达式] 第一节:C# 3.0 是什么 & C# 3.0的适用范围 
C# 3.0 入门系列(一) 
  什么都不做的Lambda表达式
 
  这个话题说到此,还有盲点。这里先说明一下什么都不做的Lambda表达式的写法。
 
  Lambda表达式没有返回值的情况(void的情况),想使其内容为空的情况下(调用后什么也不执行的Lambda表达式选择使用的情况),可以使用内容为空的Lambda语句。
 
  例如,下面这个的Lambda表达式:
 
  (x) => { };
 
  这样用Lambda表达式重构,解决了“引入了null值对象”的问题。一句话,不应该用null表示什么也不做的表达式,而是采用调空Lambda表达式的手法。
 
  简单的说,分别用代码来展示能够使用和不能够使用这个技术的场合。
 
  首先,说说不能够使用该技术的场合。下面的代码,因为什么也不需要处理,所以用null值表示的例子。Sample方法的参数action,仅在值不为null的情况下被调用。
 
using System;
 
class Program
{
  private static void Sample(Action<string> action)
  {
    if (action != null) action("Hello!");
  }
 
  static void Main(string[] args)
  {
    Action<string> action = null;
    Sample(action);
 
    action = (x) => Console.WriteLine(x);
    Sample(action); // 输出:Hello!
  }
}
 
  List 16 执行时没什么可处理的情况下用null表示的例子
 
  相反,下面的代码,在没什么要执行的情况下,要使用空Lambda表达式表示的情况。没必要判定Sample方法的参数action是否为null。如果需要处理的内容不存在的情况下,仅仅用空的Lambda表达式来执行,什么也不做就返回。
 
 
using System;
 
class Program
{
  private static void Sample(Action<string> action)
  {
    action("Hello!");
  }
 
  static void Main(string[] args)
  {
    Action<string> action = (x) => { };
    Sample(action);
 
    action = (x) => Console.WriteLine(x);
    Sample(action); // 输出:Hello!
  }
}
 
  List 17 没什么可处理的情况下用空表达式的例子
 
  这样的“什么也不做的Lambda表达式(或是以前的匿名方法)”,是笔者经常使用的技术。
 
  例如,现在正在写的程序,具有用户的操作用报表的形式回放的功能,通过该功能进行自动测试。这个时候,回放中与输出有关的处理会全部禁用,以提高其运行效率。这些操作的实现,并不需要具有输出功能的方法对条件进行一个一个的判断,只要用“空Lambda表达式(匿名方法)”就行了。因此,源代码仍然能够维持其简洁,成功实现了随时都能够执行的自动测试效率的目的。
 
 
编缉推荐阅读以下文章
 
[C# 3.0 入门] [第一章 Lambda表达式] 第五节:Lambda表达式的使用范例 & Lambda表达式的各种变体 
[C# 3.0 入门] [第一章 Lambda表达式] 第三节:Lambda与匿名方法的区别 
[C# 3.0 入门] [第一章 Lambda表达式] 第二节:Lambda表达式带来了什么 
[C# 3.0 入门] [第一章 Lambda表达式] 第一节:C# 3.0 是什么 & C# 3.0的适用范围 
C# 3.0 入门系列(一) 
using System;
 
class Program
{
  static void Main(string[] args)
  {
    Action<bool> method =
      (system) => System.IO.File.AppendAllText(
          system ? "system.log" : "normal.log", "log message\r\n");
 
    method(false); // 生成normal.log 
    method(true); // 生成system.log 
  }
}
 
  List12 使用三元运算符(?:)的Lambda表达式
 
  但是,前一章的List10的例子里,其中的if语句中就不能改用三元运算符来替换。如果试图替换的话就是以下情况:
 
using System;
 
class Program
{
  static void Main(string[] args)
  {
    Action<string> method = (filename) =>
      filename == null
        ? Console.WriteLine("Hello!")
        : System.IO.File.WriteAllText(filename, "Hello!");
 
    method(null);
    method("hello.txt");
  }
}
 
  List13 List10中用三元运算符改写后(产生编译错误)
 
  这个代码,会产生以下的编译错误:
 
  error CS0201: 只有 assignment、call、increment、decrement 和 new 对象表达式可用作语句。
 
  error CS0173: 无法确定条件表达式的类型,因为“void”和“void”之间没有隐式转换。
 
  这并不是说Lambda表达式不能调用具有void返回值的方法。下面的代码就没有问题。
 
Action<string> method =
  (filename) => System.IO.File.WriteAllText(filename, "Hello!");
 

相关教程