新Orcas语言特性:扩展方法 为程序扩展方法

来源:互联网 发布:em算法实例 编辑:程序博客网 时间:2024/04/30 12:14

 

新Orcas语言特性:扩展方法

【原文地址】New "Orcas" Language Feature: Extension Methods
【原文发表日期】 Tuesday, March 13, 2007 2:27 AM

上个星期,我发表了我准备写的讨论一些新的VB和C#语言特性的系列博客贴子的第一篇,这些新语言特性是将于今年晚些时候发布的Visual Studio和.NET框架Orcas版的一部分。

我的上一个博客贴子讨论了自动属性,对象初始化器和集合初始化器等新特性。如果你还没有读过这个帖子的话,请在这里阅读。今天的贴子讨论一个VB和C#中都具有的,重要得多的新特性:扩展方法 (Extension Methods)

什么是扩展方法 (Extension Methods)?

扩展方法允许开发人员往一个现有的CLR类型的公开契约(contract)中添加新的方法,而不用生成子类或者重新编译原来的类型。扩展方法有助于把今天动态语言中流行的对duck typing的支持之灵活性,与强类型语言之性能和编译时验证融合起来。

扩展方法促成了好多有用的使用场景,并使在作为Orcas一部分发布的.NET版本中引进的非常强大的LINQ查询框架成为可能。

简单的扩展方法例子:

有没有想过要检查一个字符串变量是否是个合法的电子邮件地址? 在今天,你大概需要通过调用一个单独的类(或许通过一个静态方法)来实现检查该字符串变量是否合法。譬如,象这样:

 

string email Request.QueryString["email"];

if 
( EmailValidator.IsValid(email) ) {
   

}

 

而使用C#和VB中的新“扩展方法”语言特性的话,我则可以添加一个有用的“IsValidEmailAddress()”方法到string类本身中去,该方法返回当前字符串实例是否是个合法的字符串。然后我可以把我的代码重写一下,使之更加干净,而且更具描述性,象这样:

 

string email Request.QueryString["email"];

if 
( email.IsValidEmailAddress() ) {
   

}

 

我们是怎么把这个新的IsValidEmailAddress()方法添加到现有的string类里去的呢?我们是通过定义一个静态的类型,带有我们的“IsValidEmailAddress”这个静态的方法来实现的,象下面这样:

 

public static class ScottGuExtensions
{
    
public static bool IsValidEmailAddress(this string s)
    {
        Regex regex 
= new Regex(@"^[/w-/.]+@([/w-]+/.)+[/w-]{2,4}$");
        return 
regex.IsMatch(s);
    
}
}

 

注意,上面的静态方法在第一个类型是string的参数变量前有个“this”关键词,这告诉编译器,这个特定的扩展方法应该添加到类型为“string”的对象中去。然后在IsValidEmailAddress()方法实现里,我可以访问调用该方法的实际string实例的所有公开属性/方法/事件,取决于它是否是合法电子邮件地址来返回true/false。

在我的代码里把这个特定的扩展方法的实现添加到string实例,我只要使用标准的“using”语句来引入含有该扩展方法的实现的命名空间:

 

using ScottGuExtensions;

 

然后编译器就会在任何string上正确地定位IsValidEmailAddress()方法。在公开发行的Orcas三月份的CTP中的C#和VB在Visual Studio代码编辑器里对扩展方法提供了完整的intellisense支持。所以,当我在一个字符串变量上点击“.”关键词时,我的扩展方法现在就会出现在intellisense的下拉框里:

VB和C#编译器也会很自然地给与你对所有扩展方法用法的编译时的检查,这意味着你会得到一个编译时错误,假如你键错或者错用一个扩展方法的话。

[感谢David Hayden是他在去年的一个老帖子 里第一个示范了我在上面使用的这个IsValidEmailAddress使用场景。]

扩展方法使用场景续...

利用扩展方法这个新特性来给个别类型添加方法给开发人员开辟了许多有用的扩展性使用场景。但使得扩展方法非常强有力的是,它们不仅能够应用到个别类型上,也能应用到.NET框架中任何基类或接口上。这允许开发人员建立种种可用于整个.NET框架的丰富的可组合的框架层扩展。

譬如,考虑这样一个场景,我想要一个既容易,描述性又强的方式来检查一个对象是否已经包含在一个对象集合或数组里。我可以定义一个简单的.In(集合)扩展方法,我想把它添加到.NET框架中的所有对象上,我可以在C#里这么来实现这个“In()”扩展方法:

注意上面我是如何声明扩展方法的第一个参数的:“this object o”。这表明,这个扩展方法应该适用于继承于基类System.Object的所有类型,这意味著我可以在.NET中的每个对象上使用它。

上面这个“In”方法的实现允许我检查一个指定的对象是否包含在作为方法参数传入的一个IEnumerable序列中。因为所有的.NET集合和数组都实现了IEnumerable接口,现在我拥有了一个有用的,描述性强的方法来检查一个任意的对象是否属于任何.NET集合或数组。

然后我就可以使用这个“In()”方法来看一个特定的字符串是否在一个字符串数组中:

我也可以用它来检查一个特定的ASP.NET控件是否在一个容器控件集合里:

我甚至可以将其用在象整数这样的标量数据类型上:

注意上面,你甚至可以在象整数值42这样的基本数据类型值上使用扩展方法。因为CLR支持数值类型的自动boxing/unboxing,扩展方法可以直接使用在数值和其他标量数据类型上。

你大概可以开始从上面的例子中看出,扩展方法可以促成一些非常丰富和描述性强的扩展性使用场景。当使用于.NET中常见的基类和接口上时,他们可以促成一些非常好的特定于某个领域(domain specific)的框架和组合使用场景。

内置的System.Linq扩展方法

一个在Orcas时段随.NET发布的内置的扩展方法库是一套允许开发人员对任何数据进行查询的非常强有力的查询扩展方法。这些扩展方法实现位于新的 System.Linq 命名空间之下,定义了标准的查询操作符扩展方法,可以为.NET开发人员用来轻松地查询XML,关系数据库,.NET 对象, 和任何其他数据结构类型。

下面是使用这些查询扩展方法的扩展性模型的几个好处:

1) 它允许一个可用于所有数据类型(数据库,XML文件,内存中的对象,以及web-services等)的共同的查询编程模型和语法。

2) 它是可以组合的,允许开发人员轻松地往查询语法中添加新的方法/操作符。譬如,我们可以将我们自定义的“In()”方法与为LINQ所定义的标准的“Where()”方法作为一个单独查询的一部分一起使用。我们自定义的In()方法看上去就跟由System.Linq命名空间提供的标准方法一样。

3) 它是可扩展的,允许与任何数据提供器类型一起使用。譬如,任何一个象NHibernate或LLBLGen这样现有的ORM引擎可以实现LINQ的标准查询操作符来允许对他们现有的ORM实现和映射引擎实现LINQ查询。这允许开发人员学会一个查询数据的共同方式,然后对种类繁多的丰富数据存储实现使用同样的技能。

我将在下几个星期里对LINQ作更多的示范,但想留给你几个例子,这些例子展示了如何对不同类型的数据使用几个内置的LINQ查询扩展方法:

使用场景一:对内存中的.NET对象使用LINQ扩展方法

假定我们象这样定义了代表“Person”的类:

然后我可以使用新的对象初始化器和集合初始化器特性创建和填充一个“people”集合,象这样:

然后我可以使用由System.Linq提供的标准的“Where()”扩展方法来获取这个集合中FirstName的首字符是"S"的那些“Person”对象,象这样:

上面这个新的 p => 语法是“Lambda表达式”的一个例子,是对C# 2.0匿名方法支持的更简明的发展,允许我们通过一个实参来轻松地表达查询过滤(在这个情形下,我们表示我们只想要返回一串firstname属性的首字符是“S”字母的Person对象) 。上面这个查询然后就会返回包含2个对象的序列,Scott 和 Susanne。

我也可以利用由System.Linq提供的新的“Average” 和“Max”扩展方法编写代码来决定我的集合里的人的平均年龄,以及年龄最大的人,象这样:

使用场景二:对XML文件使用LINQ扩展方法

你手工在内存里创建一个硬写(hard-coded)的数据集合大概是很少见的。更有可能的是,你会从一个XM文件,数据库,或web服务里获取数据。

假定我们在硬盘上有一个XML文件,包含下面这样的数据:

很明显地,我可以使用现有的 System.Xml APIs 来装载这个XML文件进一个DOM,然后访问它,或者使用一个层次较低的XmlReader API ,自己对之手工分析。或者,在 Orcas中,我现在也可以使用支持标准的LINQ扩展方法的System.Xml.Linq 实现(即 XLINQ),更优雅地分析和处理XML。

下面的代码例子展示了如何使用LINQ来获取所有包含一个子节点的值的首字母为“S”的<person> XML元素:

注意,它使用了跟内存中对象例子中一模一样的 Where() 扩展方法。现在它返回一个“XElement”元素序列,XElemen是没有类型的XML节点元素。或者我也可以重写查询表达式,通过LINQ的 Select() 扩展方法来构造数据形状,提供一个使用了新的对象初始化器句法的Lambda 表达式来填充同样的“Person”类,跟我们第一个内存中的集合的例子一样:

上面的代码会做需要打开,分析,和过滤XML,然后返回一个强类型的Person对象序列所有的工作,不需要什么映射或持久的文件来映射数值,我只是在上面的LINQ查询式里直接指明了从XML到对象的构形而已。

我也可以和前面一样使用同样的Average() 和 Max() LINQ扩展方法来计算XML文件中<person>元素的平均年龄,以及最大年龄,象这样:

我不用手工分析XML文件,XLINQ 不仅可以为我处理分析,它在估算LINQ表达式时,也可以使用低层的XMLReader,而不是使用DOM来分析文件。这意味着它是迅速之极,而且不分配很多内存。

使用场景三:对数据库使用LINQ扩展方法

假定我们拥有一个SQL数据库,内含一个叫“People”的表,具有下列数据定义:

我可以使用Visual Studio中新的LINQ到SQL的所见即所得(WYSIWYG) ORM设计器,快速地创建一个映射到数据库的“Person”类:

然后我可以使用我先前用于对象和XML文件同样的LINQ Where() 扩展方法,从数据库中获取firstname的首字符为“S”的强类型“Person”对象序列:

注意,查询句法与对象和XML场景中的一模一样。

然后我也可以使用与前面一样的 LINQ Average() 和Max() 扩展方法来从数据库里获取平均和最大值,象这样:

要使上面代码例子工作,你自己不需编写任何SQL代码。Orcas中提供的LINQ到SQL对象关系映射器会处理获取,跟踪,和更新映射到你的数据库数据定义和存储过程的对象。你只要使用任何LINQ扩展方法对结果进行过滤和构形即可,LINQ到SQL会执行获取数据所需的SQL代码(注意,上面的 Average和Max 扩展方法很明显地不会从数据表中返回所有的数据行,它们会使用TSQL的聚合函数来计算数据库中的值,然后只返回一个标量值)。

请观看我一月份制作的一个录像,演示了LINQ到SQL如何显著地改进了Orcas中的数据生产力。录像中,你也可以看到新的LINQ到SQL的所见即所得ORM设计器的实战示范,以及对数据模型编写LINQ代码时代码编辑器提供的完整的 intellisense。

结语

希望上面的帖子给了你一个对扩展方法工作原理的基本理解,以及你能够利用它们来实现的一些酷扩展性方式。跟任何扩展性机制一样,我要告诫你别一开始就滥建新的扩展方法。不能因为你有一个闪亮的新榔头,就意味着世界上所有的东西突然都变成钉子了!

想着手开始尝试扩展方法的话,我建议你先探究一下Orcas中System.Linq命名空间中提供的标准查询操作符。这些操作符提供了对任何数组,集合,XML流,或关系数据库做丰富的查询的支持,可以极大地改进你操作数据时的生产力。我认为你会发现它们极大地减小了你要在你应用中编写的代码量,允许你编写非常干净和描述性强的语句。它们也允许你在你编码中得到查询逻辑自动的intellisense 和编译时检查。

在下几个星期里,我将继续这个关于Orcas中新语言特性的系列,探讨匿名类和类的推断(Type Inference),还会讨论Lambda的细节和其他酷特性。很明显地,我还会地更多地讨论LINQ。

希望本文对你有所帮助,

Scott

标签: ASP.NET, .NET, LINQ, Data, SQL Server

打印 | 张贴于 2007-04-07 02:38:00 | Tag:ASP.NET  .NET  LINQ  Data  SQL Server

留言反馈

[转贴].NET3.5新特性,Lambda表达式 编辑
【原文地址】New
2008-02-13 21:01:00 | [匿名:菩提树下的杨过]
VS2008学习之路 转载 编辑
VS2008学习之路 转载
2008-01-29 13:28:00 | [匿名:zym12021]
Visual Studio 2008 和 .NET 3.5 发布了 编辑
【原文地址】VisualStudio2008and.NET3.5Released 【原文发表日期】Monday,November19,200710:34AM 今天我们发布...
2008-01-25 19:33:00 | [匿名:宏宇]
新Orcas语言特性:扩展方法 编辑
新Orcas语言特性:扩展方法
2008-01-24 11:05:00 | [匿名:都市剑客]
VS 2008 和 .NET 3.5 Beta 2 发布了 编辑
我非常高兴地宣布,VS 2008和.NET 3.5的Beta2版本可以下载了。你可以在这里下载Visual Studio 2008产品。你也可以在这里下载较小的VS 2008 Express版本。
2008-01-08 16:33:00 | [匿名:小鱼儿]
Visual Studio 2008 和 .NET 3.5 发布了 编辑
【原文地址】VisualStudio2008and.NET3.5Released 【原文发表日期】Monday,November19,200710:34AM 今天我们发布...
2008-01-08 16:00:00 | [匿名:吴华朋]
ASP.NET MVC框架(第四部分): 处理表单编辑和提交场景 编辑
【原文地址】ASP.NETMVCFramework(Part4):HandlingFormEditandPostScenarios 【原文发表日期】Sunday,Decem...
2008-01-05 08:47:00 | [匿名:幸福]
Visual Studio 2008 和 .NET 3.5 发布了 编辑
【原文地址】VisualStudio2008and.NET3.5Released 【原文发表日期】Monday,November19,200710:34AM 今天我们发布...
2008-01-05 08:43:00 | [匿名:幸福]
VS2008学习之路 编辑
[1]新的C#语言特性:自动属性(AutomaticProperties) public
2008-01-04 09:40:00 | [匿名:大力bober]
VS2008学习之路 编辑
[1]新的C#语言特性:自动属性(AutomaticProperties) public
2008-01-02 15:51:00 | [匿名:大力bober]
回复: 新Orcas语言特性:扩展方法 编辑
强! 

正在搞.NET3.5
2008-01-02 15:17:00 | [匿名:dali]
 C#3.0 中的扩展方法 (Extension Methods) 编辑
今天早上在MSDN站点看到这样一篇文章:C#3.0LINQ的演变及其对C#设计的影响
2007-12-17 12:26:00 | [匿名:csdnexpert]
C#3.0介绍 编辑
以下资源仅供大家参考: 1、自动属性,对象初始化器,和集合初始化器 2、新Orcas语言特性:扩展方法 3、新Orcas语言特性:Lambda表达式 4、新Orcas语言特性:查询句法...
2007-11-27 18:19:00 | [匿名:曹振华]
C#3.0介绍 编辑
以下资源仅供大家参考: 1、自动属性,对象初始化器,和集合初始化器 2、新Orcas语言特性:扩展方法 3、新Orcas语言特性:Lambda表达式 4、新Orcas语言特性:查询句法...
2007-11-27 18:19:00 | [匿名:曹振华]
Visual Studio 2008 和 .NET 3.5 发布了 编辑
转自:http://blog.joycode.com/scottgu/archive/2007/11/20/111568.aspx
2007-11-27 17:53:00 | [匿名:曹振华]
Visual Studio 2008 和 .NET 3.5 发布了 编辑
今天我们发布了VisualStudio2008和.NET3.5。你可以使用下面的链接下载其最终版: 如果你是MSDN订阅者,你可以在MSDN订阅网站下载(注:其中...
2007-11-20 16:44:00 | [匿名:大口仔]
Visual Studio 2008 和 .NET 3.5 发布了 编辑
转自:http://blog.joycode.com/scottgu/archive/2007/11/20/111568.aspx
2007-11-20 15:19:00 | [匿名:Randy0528]
回复: 新Orcas语言特性:扩展方法 编辑
美捷科技(北京)有限公司是一家致力于数字化期刊出版,期刊采编,[URL=http://www.meijiebj.com]期刊采编软件[/URL]开发,以追求采编出版自由和文化繁荣为己任的高科技企业!
2007-11-08 14:18:00 | [匿名:sfeas]
技巧/诀窍:用 .NET 3.5 创建 ToJSON() 扩展方法 (木野狐译) 编辑
【原文地址】 Tip/Trick: Building a ToJSON() Extension Method using .NET 3.5 【原文发表日期】 Monday, October 01, 2007
2007-10-10 10:53:00 | [匿名:Joycode@Ab110.com]
C#3.0 中的扩展方法 (Extension Methods) (转) 编辑
今天早上在MSDN站点看到这样一篇文章:C#3.0LINQ的演变及其对C#设计的影响
2007-09-11 17:47:00 | [匿名:徐钢]
C#3.0 中的扩展方法 (Extension Methods) 编辑
今天早上在MSDN站点看到这样一篇文章:C#3.0LINQ的演变及其对C#设计的影响
2007-09-11 17:46:00 | [匿名:徐钢]
VS 2008 和 .NET 3.5 Beta 2 发布了(转帖) 编辑
VS 2008 和 .NET 3.5 Beta 2 发布了(转帖)
2007-09-06 22:38:00 | [匿名:IMustDo]
C#3.0美文收集 编辑
今天在蝈蝈俊.net上看到一个关于.net3.0好文章收集的帖子,就顺手转了过来。 另外我又加了李建忠老师C#3.0锐利体验系列课程的链接,以后如果发现好的 将会继续更新。 大家如果有什么好的文章...
2007-09-01 22:33:00 | [匿名:张荣华]
回复: 新Orcas语言特性:扩展方法 编辑
值得已读,对LINQ的查询功能实在刮目想看!
2007-08-28 00:24:00 | [匿名:ricky52529]
新Orcas语言特性:查询句法 编辑
新Orcas语言特性:查询句法
2007-08-22 10:08:00 | [匿名:BoardPung]
关于 Orcas 信息收集 编辑
本节收集关于Orcas的信息,便于以后学习和交流。
2007-08-21 10:41:00 | [匿名:SmartSoft]
VS 2008 和 .NET 3.5 Beta 2 发布了 编辑
VS2008和.NET3.5Beta2发布了 【原文地址】VS2008and.NET3.5Beta2Released【原文发表日期】Thursday,July...
2007-08-17 13:52:00 | [匿名:ejiyuan]
VS 2008 和 .NET 3.5 Beta 2 发布了 编辑
【原文地址】 VS 2008 and .NET 3.5 Beta 2 Released 【原文发表日期】 Thursday, July 26, 2007 2:11 PM 我非常高兴地宣布,VS 2008和
2007-07-30 12:17:00 | [匿名:Joycode@Ab110.com]
新Orcas语言特性:Lambda表达式。 编辑
随VS 2005发布的C#2.0引进了匿名方法的概念,允许在预期代理(delegate)值的地方用“行内(in-line)”代码块(code blocks)来做替代。 
2007-06-25 00:37:00 | [匿名:勤勤同学]
C#3.0 中的扩展方法 (Extension Methods) 编辑
今天早上在MSDN站点看到这样一篇文章: C# 3.0 LINQ 的演变及其对 C# 设计的影响 。 从这篇文章我们就可以明显的看到,C# 3.0 所新增的这些特性,可以认为都是为了LINQ 的发展,为了LINQ更易用
2007-06-06 11:36:00 | [匿名:Joycode@Ab110.com]
C#3.0 中的扩展方法 (Extension Methods) 编辑
今天早上在MSDN站点看到这样一篇文章: C# 3.0 LINQ 的演变及其对 C# 设计的影响
2007-06-06 11:28:00 | [匿名:ghj1976]
新Orcas语言特性:匿名类型 编辑
【原文地址】 New &quot;Orcas&quot; Language Feature: Anonymous Types 【原文发表日期】 Tuesday, May 15, 2007 7:02 AM
2007-05-21 10:26:00 | [匿名:Joycode@Ab110.com]
LINQ篇:查询句法[转] 编辑
2007-04-25 20:47:00 | [匿名:MonkRui]
[不搜集不行]新Orcas语言特性:查询句法 编辑
fromhttp://weblogs.asp.net/scottgufromhttp://blog.joycode.com/scottgu/archive/2007/04/24/101654.as...
2007-04-24 22:43:00 | [匿名:ColdDog]
新Orcas语言特性:Lambda表达式 编辑
什么是Lambda表达式?Lambda表达式为编写匿名方法提供了更简明的函数式的句法,但结果却在编写LINQ查询表达式时变得极其有用,因为它们提供了一个非常紧凑的而且类安全的方式来编写可以当作参数来传递,在以后作运算的函数。
2007-04-10 13:38:00 | [匿名:shoutor]
新Orcas语言特性:扩展方法 编辑
什么是扩展方法 (Extension Methods)?扩展方法允许开发人员往一个现有的CLR类型的公开契约(contract)中添加新的方法,而不用生成子类或者重新编译原来的类型。扩展方法有助于把今天动态语言中流行的对duck typing的支持之灵活性,与强类型语言之性能和编译时验证融合起来。
2007-04-10 13:35:00 | [匿名:shoutor]
新Orcas语言特性:Lambda表达式 编辑
什么是Lambda表达式?Lambda表达式为编写匿名方法提供了更简明的函数式的句法,但结果却在编写LINQ查询表达式时变得极其有用,因为它们提供了一个非常紧凑的而且类安全的方式来编写可以当作参数来传递,在以后作运算的函数。
2007-04-10 13:35:00 | [匿名:shoutor]
回复: 新Orcas语言特性:扩展方法 编辑
看来 orcas的新功能还真不少,期待中
2007-04-07 21:12:00 | [匿名:cgdou]
回复: 新Orcas语言特性:扩展方法 编辑
这篇文章我好几天前就看了英文原版了。确实很值得仔细一读。可以让你感受到C# 3.0的强大。
轉自 http://blog.joycode.com/scottgu/archive/2007/04/07/100611.aspx

 

原创粉丝点击