这几天研究了一下Linq,C# 3.0中的“扩展方法”特性为IEnumerable<T>增加了诸如Where、Select等查询方法,这使得“语言集成查询”成为顺其自然的事情。而C#3.0中Linq的实现也是建立在C#2.0的匿名委托的特性之上。
今天,我尝试在C#2.0中使用匿名委托模拟C#3.0中Where、Select等查询方法的实现。我将所有的查询方法作为静态方法在GenericHepler静态类中实现。
之前,我们先定义泛型委托:
publicdelegateTResultFunc<T,TResult>(Tsource);
这个委托在后面的实现中需要用到。
作为基础,首先,我们需要实现ForSpecification方法,该方法的含义是:对集合中满足指定条件的元素执行指定方法调用。
///<summary>
///ForSpecification对集合中满足predicate条件的元素执行action。如果没有条件,predicate传入null。
///</summary>
publicstaticvoidForSpecification<TSource>(IEnumerable<TSource>collection,Action<TSource>action,Predicate<TSource>predicate)
{
if(predicate==null)
{
foreach(TSourceobjincollection)
{
action(obj);
}
return;
}
foreach(TSourceobjincollection)
{
if(predicate(obj))
{
action(obj);
}
}
}
有了ForSpecification的实现,我们就可以在其基础上实现ForEach和ForFirstSpecification:
#regionForEach
///<summary>
///ForEach对集合中的每个元素执行action。
///</summary>
publicstaticvoidForEach<TSource>(IEnumerable<TSource>collection,Action<TSource>action)
{
GenericHepler.ForSpecification<TSource>(collection,action,null);
}
#endregion
#regionForFirstSpecification
///<summary>
///ForSpecification对集合中第一个满足predicate条件的元素执行action。如果没有条件,predicate传入null。
///</summary>
publicstaticvoidForFirstSpecification<TSource>(IEnumerable<TSource>collection,Action<TSource>action,Predicate<TSource>predicate)
{
if(predicate==null)
{
foreach(TSourceobjincollection)
{
action(obj);
break;
}
}
else
{
foreach(TSourceobjincollection)
{
if(predicate(obj))
{
action(obj);
break;
}
}
}
}
#endregion
有了ForSpecification,我们就可以实现查询方法Where:
#regionWhere
///<summary>
///Where从集合中选取符合条件的元素
///</summary>
publicstaticIList<TSource>Where<TSource>(IEnumerable<TSource>source,Predicate<TSource>predicate)
{
IList<TSource>list=newList<TSource>();
GenericHepler.ForSpecification(source,delegate(TSourceele){list.Add(ele);},predicate);
returnlist;
}
#endregion
对于C#3.0中的Select方法,其实现需要匿名类型的支持,而C#2.0中不支持匿名类型,所以,我用泛型来代替。我使用ConvertSpecification来模拟Select实现:
#regionConvertSpecification
///<summary>
///ConvertSpecification将source中的符合predicate条件元素转换为TResult类型
///</summary>
publicstaticIList<TResult>ConvertSpecification<TSource,TResult>(IEnumerable<TSource>source,Func<TSource,TResult>converter,Predicate<TSource>predicate)
{
IList<TResult>list=newList<TResult>();
GenericHepler.ForSpecification<TSource>(source,delegate(TSourceele){list.Add(converter(ele));},predicate);
returnlist;
}
#endregion
converter委托用于从TSource类型对象构造TResult类型的对象。
有了ConvertSpecification实现,我们就可以在其上继续实现ConvertAll和ConvertFirstSpecification:
#regionConvertAll
///<summary>
///ConvertAll将source中的每个元素转换为TResult类型
///</summary>
publicstaticIList<TResult>ConvertAll<TSource,TResult>(IEnumerable<TSource>source,Func<TSource,TResult>converter)
{
returnGenericHepler.ConvertSpecification<TSource,TResult>(source,converter,null);
}
#endregion
#regionConvertFirstSpecification
///<summary>
///ConvertSpecification将source中的符合predicate条件的第一个元素转换为TResult类型
///</summary>
publicstaticTResultConvertFirstSpecification<TSource,TResult>(IEnumerable<TSource>source,Func<TSource,TResult>converter,Predicate<TSource>predicate)
{
TSourcetarget=GenericHepler.GetFirstSpecification<TSource>(source,predicate);
if(target==null)
{
returndefault(TResult);
}
returnconverter(target);
}
#endregion
有了上面的基础,我们还可以实现ContainsSpecification方法:
#regionContainsSpecification
///<summary>
///ContainsSpecification集合中是否包含满足predicate条件的元素。
///</summary>
publicstaticboolContainsSpecification<TSource>(IEnumerable<TSource>source,Predicate<TSource>predicate,outTSourcespecification)
{
specification=default(TSource);
foreach(TSourceelementinsource)
{
if(predicate(element))
{
specification=element;
returntrue;
}
}
returnfalse;
}
#endregion
#regionContainsSpecification
///<summary>
///ContainsSpecification集合中是否包含满足predicate条件的元素。
///</summary>
publicstaticboolContainsSpecification<TSource>(IEnumerable<TSource>source,Predicate<TSource>predicate)
{
TSourcespecification;
returnGenericHepler.ContainsSpecification<TSource>(source,predicate,outspecification);
}
#endregion
代码中的注释已经将各个方法的用途说得非常清楚,下面我们举两个例子来看看如何使用它们以发挥它们的威力!
例子一:比如,我们要从当前玩家(IPlayer)列表中找出所有年龄大于30岁的玩家的ID,通常这样做:
publicIList<string>GetOldPlayer()
{
IList<string>results=newList<string>();
foreach(IPlayerplayerinthis.playerList)
{
if(player.Age>30)
{
results.Add(player.ID);
}
}
returnresults;
}
如果使用上面我们封装的API,则可以非常简单地达到目的:
publicIList<string>GetOldPlayer()
{
returnGenericHepler.ConvertSpecification<IPlayer,string>(this.playerList,delegate(IPlayerplayer){returnplayer.ID;},delegate(IPlayerplayer){returnplayer.Age>30});
}
一句搞定。
例子二:我们要从当前的玩家字典(Dictionary)中取出所有ID不是指定集合中的ID的其它玩家列表。
通常,我们可以这样做:
publicIList<IPlayer>GetPartners(paramsstring[]excludedUserIDs)
{
IList<IPlayer>partnersList=newList<IPlayer>();
foreach(stringuserIDinthis.dicPlayers.Keys)
{
boolexclude=false;
foreach(stringexcludedUserinexcludedUserIDs)
{
if(userID==excludedUser)
{
exclude=true;
break;
}
}
if(!exclude)
{
partnersList.Add(this.dicPlayers[userID]);
}
}
returnpartnersList;
}
使用上面我们封装的API,则非常简单:
publicIList<IPlayer>GetPartners(paramsstring[]excludedUserIDs)
{
returnGenericHepler.Where<IPlayer>(this.dicPlayers.Values,delegate(IPlayerplayer){return!GenericHepler.ContainsSpecification<string>(excludedUserIDs,delegate(stringid){returnid==player.UserID;});});
}
灵活地使用这些API,我们可以非常简洁地操作集合中的元素。
最后给出GenericHepler类的源码下载,其中还包含了几个未介绍的实用的API。
分享到:
相关推荐
C#2.0新特性C#2.0新特性
开发人员必看的C#2.0教程,开发人员必看的C#2.0教程开发人员必看的C#2.0教程
C#2.0示例
C#2.0 餐饮管理系统,C#2.0 餐饮管理系统,C#2.0 餐饮管理系统,C#2.0 餐饮管理系统,C#2.0 餐饮管理系统,C#2.0 餐饮管理系统,
本书介绍了微软最新的编程语言C# 2.0,全书共分7篇共18章,从基础到应用,内容涉及C# 2.0语法、面向对象编程、使用Visual Studio 2005快速可视化编辑器、.NET类库的使用、使用ADO.NET 2.0进行数据库编程,以及使用C#...
C#2.0标准文档(官方语言规范),涉及了C#2.0语法的各个方面(是规范不是教程),仔细看一遍就知道你那些还没有掌握了。
C#2.0中的 压缩操作例子
运行环境:SQL SERVER2005+VS2005+c#2.0,项目绝对完整!谢谢支持。
C#2.0完全参考手册源代码供大家使用!
完全手册:c#2.0程序设计详解电子教程完全手册:c#2.0程序设计详解电子教程
C#2.0 泛型和强制类型转换C#2.0 泛型和强制类型转换C#2.0 泛型和强制类型转换
C#2.0企业人事管理系统C#2.0企业人事管理系统C#2.0企业人事管理系统C#2.0企业人事管理系统C#2.0企业人事管理系统
c#2.0中动态修改页面标题c#2.0中动态修改页面标题c#2.0中动态修改页面标题
C# 2.0 宝典的随书源代码,很不错的一本书。里面的cs和bs的两个学生管理系统非常经典。值得学习!
C#2.0完全参考手册.不错的工具书。相当于msdn。免费提供给大家
该CHM介绍了c#2.0的一些新语法特性
C#2.0的新增特性
C#2.0锐利体验
c#2.0的讲解,包括c#2.0简介,泛型,匿名方法,迭代器和不完全类的内容。
c#2.0 宝典 源文件21-25