相关说明

这篇文章来自发布在MVP 项目组博客上的文章: http://blogs.msdn.com/b/mvpawardprogram/archive/2012/03/26/c.aspx
英文版: http://blogs.msdn.com/b/mvpawardprogram/archive/2012/03/26/introduction-of-new-features-in-c-5-0.aspx

正文

C#如今已经发展到5.0版本,CLR版本为4.5,伴随Visual Studio 2011发布。我总结了一个进化图,以供大家参考。


在C# 5.0中主要增加了Async Programming 以及Caller Information两个特性,以下分别作介绍。

Async Feature

在C# 5.0新增了async修饰符以及await操作符;标记有async的方法被称为异步方法。
异步编程可以给我们带来很大的便利。比如在WinForm编程中,当我们使用HttpWebRequest请求网络资源的时候,
如果使用同步请求,那么如果请求响应时间过长,会导致我们的UI线程堵塞,
从直观上的感受是窗体无响应或者无法进行UI交互操作。

private void btnTest_Click(object sender, EventArgs e)

{

var request = WebRequest.Create(txtUrl.Text.Trim());

var content=new MemoryStream();

using (var response = request.GetResponse())

{

using (var responseStream = response.GetResponseStream())

{

responseStream.CopyTo(content);

}

}

txtResult.Text = content.Length.ToString();

}



当点击Test按钮后,在txtResult显示结果之前,我们将不能对窗体进行任何操作。

在没有async之前,我们一般也可以使用BeginGetResponse方法进行异步操作,如MSDN文档上的示例所示,
我们需要编写大量的代码去实现异步的效果:
http://msdn.microsoft.com/zh-cn/library/system.net.httpwebrequest.begingetresponse(v=vs.80).aspx

下面我们将对以上的窗体进行改造,使用新增的异步编程特性,代码如下:

private async void btnTest_Click(object sender, EventArgs e)


{

var request = WebRequest.Create(txtUrl.Text.Trim());

var content = new MemoryStream();

Task<WebResponse> responseTask = request.GetResponseAsync();

using (var response = await responseTask)

{

using (var responseStream = response.GetResponseStream())

{

Task copyTask = responseStream.CopyToAsync(content);

//await operator to supends the excution of the method until the task is
completed. In the meantime, the control is returned the UI thread.

await copyTask;

}

}

txtResult.Text = content.Length.ToString();

}

通过await,可以使我们在语义上让我们理解为reponse为异步执行后的结果,而编译器会负责所有的代码生成,
我们无需再去操作复杂的Callback。这样为我们异步编程节省很多的时间。从直观上,当我们使用以上代码后,
窗体在点击Test按钮后,我们还可以进行交互操作。

Caller Information

从字面上,我们可以理解为在被调用者方法中可以获得调用者的信息,这对我们开发跟踪、
调试以及诊断工具的时候特别有用。而在之前,我们可能需要在调用者方法中自己进行相关操作,
比如插入日志信息记录哪个方法执行了等。我印象很深的是,我参与的一个项目根据要求使用微软的企业库,
在调用每个Data Access的方法前都要插入调用者的信息到日志中,以便跟踪调查等;
这样导致每个调用者方法都会有相同的调用记录日志的方法的代码。有了Caller Information,
我们可以在被调用者方法中获得以下几个信息:

CallerFilePathAttribute 调用者方法所在的源文件地址

CallerLineNumberAttribute 方法被调用的行号

CallerMemberNameAttribute 调用方法的名称

下面我将举例说明。

在以前我们可能会用到如下的方法:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace ConsoleApplicationTest

{

class Program

{

static void Main(string[] args)

{

InsertLog("Main");

MethodB();

Console.ReadLine();

}

static void MethodA()

{

InsertLog("MethodA");

MethodB();

}

static void MethodB()

{ }

static void InsertLog(string methodName)

{

Console.WriteLine("{0} called method B at {1}", methodName,
DateTime.Now);

}

}

}

在Main和MethodA中都调用了InsertLog方法。有了新特性的支持,我们可以修改代码为:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Runtime.CompilerServices;

using System.Text;

using System.Threading.Tasks;

namespace ConsoleApplicationTest

{

class Program

{

static void Main(string[] args)

{

//InsertLog("Main");

MethodB();

Console.ReadLine();

}

static void MethodA()

{

//InsertLog("MethodA");

MethodB();

}

static void MethodB(

[CallerMemberName] string memberName = "",

[CallerFilePath] string sourceFilePath = "",

[CallerLineNumber] int sourceLineNumber = 0)

{

InsertLog(memberName);

}

static void InsertLog(string methodName)

{

Console.WriteLine("{0} called method B at {1}", methodName,
DateTime.Now);

}

}

}

总结

C# 5.0新增的特性可以提高我们编程的效率同时减少代码量,VS11 IDE方面也新增加了很多新的功能,
大家可以慢慢去体会。