| 加入收藏| 设为首页| 联系我们

首页 站长学习 站长之家 源码下载 建站素材 书籍教程 常用工具
 您现在的位置: 动力中国 >> 网络编程 >> C#教程 >> 文章正文  
 [组图]C#3.0之匿名方法的实现与应用
 

C#3.0之匿名方法的实现与应用

http://www.domcn.org  文章来源:本站收藏  点击数:

  关键字:C#3.0之匿名方法的实现与应用

1. 匿名溯源

    匿名的历史可谓由来已久,在C#2.0中匿名方法就已经大量使用在委托(delegate)的应用场景中。下面我举几个例子大家可以简单回顾一下:

1) 当我们需要调用一个回调方法时,不需要构建委托对象,只需要将回调方法名传入,CLR会替我们完成委托对象的创建工作。

//example 1 
public static void CallBackWithoutANewDelegateObject()
{
//这里QueueUserWorkItem方法需要一个委托作为参数,
//但我们仅仅传递给回调方法名,CLR可以自动为我们构造出委托对象的代码
ThreadPool.QueueUserWorkItem(SomeAsyncTask, 5);
}

private static void SomeAsyncTask(object o)
{
Console.WriteLine(o);
}
   这个例子中我们没有构造出任何委托对象,而仅仅传递了回调方法名称,CLR帮我构建了创建委托对象的代码。
   2)我们甚至不用显式定义回调方法,只需要使用delegate关键字内联的写出方法代码执行调用。
//example 2 
public static void CallbackWithoutNewingADelegateObject()
{
//我们在这儿以内联形式写出回调方法体,而没有定义任何的回调方法
ThreadPool.QueueUserWorkItem(
delegate(object o) { Console.WriteLine(o); },
5);
}
   这个例子中我们并没有定义上面的方法SomeAsyncTask,而是内联写出方法体。

   3)我们甚至可以不写出调用方法的参数,CLR也会为我们生成正确的委托对象。
//example 3 
this.BT_LOGIN.Click +=
delegate { MessageBox.Show(Button Login has been clicked!); };
    这是匿名方法最常见的使用场景,即在添加一个控件的事件处理函数时直接使用delegate写出方法代码而不需要另外定义方法函数。当我们的事件处理函数很简短时(比如上面的代码我们仅仅弹出一个对话框显示一条信息而已。)我们就可以使用这种方法,如果另外定义一个函数就会显得很累赘。而且方法的参数也可以省略(比如这里的Object sender, EventArgs e)
12. C#3.0中的匿名方法

1) 隐式类型变量 (Implicitly typed local variables)
var var1 = 1; 
var var2 = 2;
var var3 = var1 + var2;

var var4 = Im a string.;
    这里我们可以看到我们并没有指定变量的类型(int , string, …),但编译器会帮我们完成这一点。熟悉脚本语言的朋友们可能会对此次语法感到惊喜,但要注意的是,C#仍然是强类型的语言,所有类型都会在编译期确定,而不是像脚本那样等到运行时,下面这张图很清楚的说明了这一点:



    大家可以看到在VS编辑器的智能提示中,编译器已经找到了变量的实际类型。这个特性在结合LINQ语言进行数据查询时显得格外有用:

    比如我们现在有一个UserInfo类,它包含了一个用户的许多信息,姓名,年龄,住址等等。

class UserInfo 
{
public string firstname;
public string lastname;
public int age;
public string address;
//...
}
   我们现在要根据年龄对数据进行一些检索,但我们希望检索结果只需要包含用户的姓名就够了,也就是firstname,和lastname这两个字段。这时候,匿名方法就可以派上用场了。
var result = from userinfo in infoList 
where userinfo.age > 20 && userinfo.age < 35
select new { userinfo.firstname, userinfo.lastname };
    大家可以看到,我们并没有返回UserInfo的整个类型,而是返回了一个只包含firstname和lastname的数据类型,编译器能够自动为我们识别出result的类型。下面我们只需要一个foreach语句就可以把数据打印出来。
foreach (var var_info in result) 
{
Console.WriteLine(var_info.firstname + + var_info.lastname);
}
    这里也同样用到了匿名类型(var var_info),下面这张图可以看出编译器可以识别出var_info的实际型别。



    有些文章在介绍C#3.0特性时会把它作为单独的特性,但我觉得这个特性也是属于编译器自动探测类型的范畴,所以仍然将它归类到匿名类型中来。 12) Lambda表达式

    前面提到在C#2.0中,我们用一个delegate关键字匿名地调用了一个委托方法,简化了程序员的工作,但同时我们也发觉程序的可读性降低了不少。下面我用一个例子来说明Lambda表达式是如何增强代码的可读性的。
还是以上面的UserInfo查询作为例子,下面的代码同样取出年龄在20-35之间的用户群。
var result1 = infoList.FindAll(p => (p.age > 20 && p.age < 35));

    这里仅仅只用了一行代码就完成了查询,是不是很神奇呢!我们来分析一下这句话的语义:首先是调用了infoList的FindAll方法,这个方法的原型如下:
// Summary: 
// Retrieves all the elements that match the conditions defined by the specified predicate.
//
// Parameters:
// match:
// The System.Predicate<T> delegate that defines the conditions of the elements
// to search for.
//
public List<T> FindAll(Predicate<T> match);
    由于篇幅原因,我删掉一部分注解,大家可以注意到它的参数Predicate<T>毫无疑问是一个委托类型,这就证明了我们前面所说的Lambda表达式确实是一个委托的简化。接着在参数中第一个字母是p,指示了我们返回的数据,这里编译器可以通过前面infoList的类型判断出p的类型来。下面是指示符”=>”,表示返回的数据集合要符合后面的查询条件。

   这里再举一个复杂一点的例子加以说明:
var groupBooksNumAndClicks = 
from book in books.Tbl_books
from type in books.Tbl_types
where book.Type_id == type.Id
group book by type.Name into g
select new { type = g.Key, booksSum = g.Count(), clicksSum = g.Sum(p => p.Clicks) };
    如果大家还有印象的话,这是我以前在介绍LINQ语言时写的一个数据库查询的例子,Tbl_books这张表包含了书籍的所有信息(书名,价格,等等),Tbl_types这张表包含了所有的书籍目录(比如数学类,计算机类等等), 我们要取出相同类别的书籍并计算每一类书籍总的点击量,有兴趣的朋友可以自行研究一下。

3. 匿名方法机理

   上面介绍了我们应当怎样使用匿名类型,下面我们通过阅读一些IL代码来看看编译器究竟为我们做了哪些工作。下面的代码演示了一个简单的匿名类型和匿名类型变量的调用,我们来看看编译器是怎么处理的。
namespace AnonymousTest 
{
class UserInfo
{
public string firstname;
public string lastname;
public int age;
public string address;
//...
}

class Program
{
static void Main(string[] args)
{
List<UserInfo> infoList = new List<UserInfo>();

var result = from userinfo in infoList
where userinfo.age > 20 && userinfo.age < 35
select new { userinfo.firstname, userinfo.lastname };

foreach (var var_info in result)
{
Console.WriteLine(var_info.firstname + + var_info.lastname);
}
}
}
}
    很简单的一段代码,首先我们定义了一个UserInfo类,其中定义了一些属性,firstname,lastname等等,这里为了简单,我们直接使用公有变量,而不使用属性来表示了。接下来就是我们的Program类,在这个类中我们定义了集合变量,由于这里仅仅为了做演示,所以实际上我并没与往集合中添加成员,但已足够让CLR生成它的结构然后我们定义了result变量去取得它的检索结果,注意我们返回的是一个匿名类型。接着我们使用freach循环将其打印出来。    下面我们打开VS的命令行窗口,输入命令ildasm,在打开的窗口中,选择File->Open打开我们编译好的文件,大家会看到如下界面:


    大家可以看到,CLR在IL层实际上是为我们新建了一个特殊的类,其中包含了firstname, secondname的属性,当然与之对应的还定义了一些set,get方法,此外,CLR还为这个类额外重载了以下方法,像Equals,ToString等等。这样我们定义的一些匿名类型就能够被编译器所识别出来。

    以上只是对匿名类型做了一个简单的介绍,有兴趣的朋友们可以从两方面继续研究它,一方面是工程上的应用,一方面继续探索IL代码的密码,无论是哪一个方面,我想你都会有很大收获的。


C#3.0之匿名方法的实现与应用
  • 上一篇文章:

  • 下一篇文章:
  •  热门文章
    普通文章 电子邮件改头换面 四公司畅谈未
    普通文章 PC病毒史上最声名狼藉的八大病
    普通文章 Rails系统中的AJAX开发技术简析
    普通文章 基于ASP.NET AJAX框架实现表单
    普通文章 开发ASP.NET AJAX客户端定制行
    普通文章 用JFreeChart对JSP报表进行增强
    普通文章 SQL Server 2005上的CLR和ADO.
    普通文章 SQL Server 2005的XML支持机制
    普通文章 Firefox中标签式浏览技巧大全
    普通文章 Tomcat中的Session和Cookie大揭
     
     推荐文章
    推荐文章 把Google地图嵌入网页 就是这么
    推荐文章 迅雷搜索候选资源出错的解决
    推荐文章 轻松去除迅雷里的各种广告和资
    推荐文章 突破限制 免费领养到QQ空间五级
    推荐文章 Rational统一过程RUP贴近中小软
    推荐文章 构建自己的轻量级XML DOM分析程
    推荐文章 WPS Office 2007技巧:妙用配置
    推荐文章 Excel 2007:求余数函数实用进阶
    推荐文章 浅谈ASP.NET的Postback
    推荐文章 软件开发中项目需求管理简述
     
     相关文章
    没有相关文章
    设为首页 | 加入收藏 | 广告合作 | 联系站长 | 版权申明 |
    动力中国为网友提供免费学习资料,可用资源,如果您认为我们的相关内容侵害到了您的权利请联系管理员
    Copyright © 2006-2008 domcn.org All Rights Reserved.