如果想发较大的信件,请用Ninputer @ gmail.com
不要在我的Blog评论中张贴广告,除非同意向我付款。
我们都知道.NET Framework 2.0支持了泛型,在它给我们带来性能收益和强类型的方便的同时,由于接口、委托等元素对泛型的支持,一些前所未有的泛型设计和算法也逐渐展现出来。
C# 2.0支持了一种叫“匿名方法”的特性,它与泛型委托结合之后,能够产生出许多诱人的新用法。比如,若想找出列表中所有大于10的元素,只需要:
List<int> l1 = new List<int>(); //populate l1 List<int> l2 = l1.FindAll(delegate(int i)...{ return i > 10; });
对于首次接触这个新特性的人来说,此语法较为费解。我们看看Generic List类的FindAll方法的定义:
public List<T> FindAll( Predicate<T> match );
我们看到,唯一的参数match是“Predicate<T>”类型的,那Predicate<T>又是什么呢,请看定义:
public delegate bool Predicate<T>( T obj );
这是一个委托,接受T类型的一个参数obj,并返回一个布尔类型,表示对obj的一个判断。现在我们就明白了,FindAll方法本应接受一个函数委托作为参数,以表示查找满足判断的所有元素,而C#的匿名方法则提供了一种就地提供函数委托的方法,使得委托的逻辑可以在同一条语句中表达。
除了Generic List,System.Array和许多其它泛型容器都提供了这种接受泛型委托的方法,在支持匿名方法的C#中,当然如鱼得水,发挥最大的作用。而VB(和多数其它的.NET语言)不支持匿名方法,在使用此类接受泛型委托的方法时,就必须单独创建一个函数,大大削弱了可读性,使用此类方法的优势也就不复存在。为了弥补此缺陷,让VB也能享受这类方法的便利,我们提出“谓词”的概念。其实“谓词”就是“判断”的一个更加名词化的说法。我们试图将常用的判断函数封装成类,使得他们可以被反复重用。首先定义一个封装Generic System.Predicate委托的类:UnaryPredicate(Of T)作为一元谓词的基类。
Public MustInherit Class UnaryPredicateClass UnaryPredicate(Of T) Public Shared Widening Operator CType(ByVal predicate As UnaryPredicate(Of T)) As Predicate(Of T) Return AddressOf predicate.PredicateProcedure End Operator Protected MustOverride Function PredicateProcedure()Function PredicateProcedure(ByVal obj As T) As Boolean End Class
我们看到这个类定义了一个与Generic Predicate委托签名相同的虚函数,用于子类实现相关的逻辑。注意,UnaryPredicate定义了一个CType运算符,将一元谓词的实例隐式转化为Generic Predicate委托。这个就是确保我们的谓词可以用在原先Generic Predicate的上下文中。
接下来我们就要实现具体的谓词。首先我们想表达关于比较的谓词,比如大于、小于、等于和不等于等等。他们都十分相似,我们看一个表示大于的谓词如何实现:
Public Class GreaterThanClass GreaterThan(Of T As IComparable(Of T)) Inherits UnaryPredicate(Of T) Private m_Value As T Public Sub New()Sub New(ByVal value As T) m_Value = value End Sub Protected Overrides Function PredicateProcedure()Function PredicateProcedure(ByVal obj As T) As Boolean Return obj.CompareTo(m_Value) > 0 End Function End Class
关键点就在于此类重写PredicateProcedure的逻辑,它表示传入的参数是否大于我们谓词自己的参数。同样,还可以定义出等于、小于等所有比较判断的谓词。
现在,我们就可以在泛型List上使用我们的谓词了,假设实现和刚才C#一样的任务:找出所有大于10的元素。
Dim l1 As New List(Of Integer) For i As Integer = 1 To 100 l1.Add(i) Next Dim l2 As List(Of Integer) l2 = l1.FindAll(New GreaterThan(Of Integer)(10))
注意最后一句,这就是我们谓词的用法,只要传入一个谓词的实例,就会被我们的基类自动转化为Generic Predicate并完成计算。而且谓词是类,因此比匿名方法有更好的重用性,并有可能达成更广泛的设计。而且这种使用谓词的语法具有相当高的可读性。
打印 | posted on Saturday, July 02, 2005 10:11 AM | Filed Under [ 技术随笔 灵感记录 ] | 收藏本页 (百度搜藏)(QQ书签)(Live收藏)(Google书签)(Yahoo书签)(新浪ViVi)(搜狐网摘)(365Key网摘)(天极网摘)(博采网摘)(和讯网摘)
Powered by:
Copyright © Ninputer