Javen-Studio 咖啡小屋

http://javenstudio.org - C++ Java 分布式 搜索引擎
Naven's Research Laboratory - Thinking of Life, Imagination of Future

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  24 随笔 :: 57 文章 :: 170 评论 :: 4 Trackbacks

3.2         扩展方法(Extension Methods

Lambda表达式是查询体系(query architecture)的一个重要部分,扩展方法(Extension methods)是另一个重要组成部分。扩展方法结合了“duck typing”(一种可替代任何类型的类型)的弹性(flexibility)特点,使得动态语言(dynamic languages,如JavaScript)更加流行(popular),同时又有静态型语言(statically typed languages,如C++Java)的优秀性能(performance)和编译时验证(compile-time validation)的特点。通过扩展方法,第三方(third parties)可以增加使用了新方法的类型(type with new methods)的公共合同(public contract),使得独立型的开发者(individual type authors)还能提供他们对这些方法的自己专门的实现(specialized implementation)。

 

扩展方法定义在静态类(static classes)里,就像静态方法(static methods)一样,但是它们在CLR元数据(CLR metadata)里却被标记为[System.Runtime.CompilerServices.Extension]。程序语言都被鼓励(encourage)为扩展方法提供一种直观的语法(direct syntax)。在 C# 语言里,扩展方法是由 this 指针(this modifer)标示(indicate)的,它必须应用于(applied to)扩展方法的第一个参数。下面让我们来看看一段最简单的查询操作符(query operator)的定义代码:

 

namespace System.Query {
  
using System;
  
using System.Collections.Generic;

  
public static class Sequence {
    
public static IEnumerable<T> Where<T>(
             
this IEnumerable<T> source,
                  Func
<T, bool> predicate) {

      
foreach (T item in source)
        
if (predicate(item))
          yield 
return item;
    }

  }

}

 

扩展方法的第一个参数的类型标示(indicate)扩展的内容所应用(the extension applies to)的类型。在上面的例子中,扩展方法 Where 扩展自 IEnumerable<T> 类型。因为 Where 是一个静态方法(static method),所以我们可以像其他静态方法一样直接调用它(invoke it directly):

 

IEnumerable<string> expr = Sequence.Where(names, 
                                          s 
=> s.Length < 6);

 

然而,扩展方法的一个独特(unique)的特点是我们还可以使用实例的语法(using instance syntax)来调用它:

 

IEnumerable<string> expr = names.Where(s => s.Length < 6);

 

扩展方法是基于扩展方法的活动范围内(in scope)在编译时(compile-time)决定的(resolved)。当引入(import)一个命名空间(namespace)时(在 C# 里使用 using 语句,在VB 里使用 Import 语句),所有的扩展方法是由从 namespace 带入活动范围(brought into scope)的静态类(static classes)定义的。

 

标准查询操作符(standard query operators)在 System.Query.Sequence 类型里定义成扩展方法。当检查标准查询操作符时,你将注意到它们中所有的方法根据(in terms of)接口IEnumerable<T> 来定义的(除了 OfType,将在后面介绍它)。这意味着每一个兼容 IEnumerable<T> 接口的信息源(information source)在 C# 语言里通过简单地添加如下的 using 语句就可以获取标准查询操作符:

 

using System.Query; // makes query operators visible

 

用户如果想用一个指定的类型(specific type)来替换标准查询操作符,可以在有一致标识(compatible signatures)的指定的类型上定义他们自己的相同名字的方法(same-named methods),另一种方法是通过扩展指定的类型来(extend the specific type)定义相同名字的方法。用户如果想完全避免(eschew)使用标准查询操作符,可以简单地将 System.Query 置于活动范围之外,并且为 IEnumerable<T> 接口写出他们自己的扩展方法就可以了。

 

按照分析规则,扩展方法被赋予了最低优先权(lowest priority),它们只是在没有相适配(suitable)的目标类型(target type)和它们的基类型(base types)时才被使用。这个规则允许用户自定的类型(user-defined types)提供他们自己的查询操作符,比标准查询操作符更优先使用(take precedence over)。例如,考虑用户自定义 collection 的实现如下:

 

public class MySequence : IEnumerable<int> {
  
public IEnumerator<int> GetEnumerator() {
    
for (int i = 1; i <= 10; i++
      yield 
return i; 
  }


  IEnumerator IEnumerable.GetEnumerator() 
{
    
return GetEnumerator(); 
  }


  
public IEnumerable<int> Where(Func<intbool> filter) {
    
for (int i = 1; i <= 10; i++
      
if (filter(i)) 
        yield 
return i;
  }

}

 

通过给出这个类的定义,下面的程序:

 

MySequence s = new MySequence();
foreach (int item in s.Where(n => n > 3))
    Console.WriteLine(item);

 

将使用 MySequence.Where 的实现,而不是扩展方法,因为类实体方法(instance methods)比扩展方法(extension methods)更优先使用。

 

前面的提及(mentioned earlier)了属于标准操作符(standard operator)一员但不是扩展自基于IEnumerable<T> 接口(IEnumerable<T>-based)的信息源的 OfType 类型,下面让我们来看看 OfTyoe 查询操作符:

 

public static IEnumerable<T> OfType<T>(this IEnumerable source) {
  
foreach (object item in source) 
    
if (item is T) 
      yield 
return (T)item;
}

 

OfType 即接受基于IEnumerable<T> 接口的信息源,也接受那些在 .NET Framework 1.0 中出现的非参数化的 IEnumerable 接口(non-parameterized IEnumerable interface)。OfType 操作符允许用户在标准的 .NET collections (classic .NET collections)上应用标准查询操作符,就像下面的程序:

 

// "classic" cannot be used directly with query operators
IEnumerable classic = new OlderCollectionType();

// "modern" can be used directly with query operators
IEnumerable<object> modern = classic.OfType<object>();

 

在这个例子中,变量 modern 产生了与变量 classic 一样的顺序的数据列表(same sequence of values),但是不同的是它的类型兼容最新的 IEnumerable<T> 代码(modern IEnumerable<T> code),包括标准查询操作符。

 

OfType 操作符对新的信息源也是有用的,因为它允许从基于类型的信息源(source based on type)中过滤出数据(filtering values from)。当要制作新的顺序的时候(producing the new sequence),OfType 简单的忽略(omits)原有序列的成员(members of the original sequence)就可以了,这是与类型实参(type argument)不相符的。分析下面的程序,目标是将 string 字符串数据从一个有不同种类数据的数组(heterogeneous array)中分解出来:

 

object[] vals = 1"Hello"true"World"9.1 };
IEnumerable
<string> justStrings = vals.OfType<string>();

 

当在 foreach 语句中列举(enumerate)变量 justStrings 中的数据时,将得到两个依次为“Hello”和“World”的 string 字符串序列(a sequence of two strings )。

 

待续, 错误难免,请批评指正,译者Naven 2005-10-22

posted on 2005-10-22 22:30 Javen-Studio 阅读(1291) 评论(3)  编辑 收藏 引用

评论

# re: 扩展方法(Extension Methods) 2008-01-16 17:38 蜜桃
为什么留那么多没有必要的原文,看的眼花缭乱?
既然是翻译,除了会引起歧义的,就没有必要留那么多原文。  回复  更多评论
  

# re: 扩展方法(Extension Methods) 2008-01-16 17:43 Javen-Studio
哦,为了方便对照着看,感觉这样会看得更仔细些:)  回复  更多评论
  

# re: 扩展方法(Extension Methods) 2008-11-18 01:12 GUYUE
看来 mitao 对自己的英文翻译很有把握啊...
不过,怎么不看见你也这么认真仔细的翻译这么好的文章呢??



谢谢分享.万分感谢。  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理