相关说明
这篇文章来自发布在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两个特性,以下分别作介绍。
在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按钮后,我们还可以进行交互操作。
从字面上,我们可以理解为在被调用者方法中可以获得调用者的信息,这对我们开发跟踪、
调试以及诊断工具的时候特别有用。而在之前,我们可能需要在调用者方法中自己进行相关操作,
比如插入日志信息记录哪个方法执行了等。我印象很深的是,我参与的一个项目根据要求使用微软的企业库,
在调用每个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方面也新增加了很多新的功能,
大家可以慢慢去体会。