【C#2.0】发挥匿名委托的威力!

这几天研究了一下Linq,C# 3.0中的“扩展方法”特性为IEnumerable<T>增加了诸如Where、Select等查询方法,这使得“语言集成查询”成为顺其自然的事情。而C#3.0中Linq的实现也是建立在C#2.0的匿名委托的特性之上。
今天,我尝试在C#2.0中使用匿名委托模拟C#3.0中Where、Select等查询方法的实现。我将所有的查询方法作为静态方法在GenericHepler静态类中实现。
之前,我们先定义泛型委托:
public delegate TResultFunc < T,TResult > (Tsource);
这个委托在后面的实现中需要用到。

作为基础,首先,我们需要实现ForSpecification方法,该方法的含义是:对集合中满足指定条件的元素执行指定方法调用。
/// <summary>
/// ForSpecification对集合中满足predicate条件的元素执行action。如果没有条件,predicate传入null。
/// </summary>
public static void ForSpecification < TSource > (IEnumerable < TSource > collection,Action < TSource > action,Predicate < TSource > predicate)
{
if (predicate == null )
{
foreach (TSourceobj in collection)
{
action(obj);
}

return ;
}

foreach (TSourceobj in collection)
{
if (predicate(obj))
{
action(obj);
}
}
}

有了ForSpecification的实现,我们就可以在其基础上实现ForEach和ForFirstSpecification:
#region ForEach
/// <summary>
/// ForEach对集合中的每个元素执行action。
/// </summary>
public static void ForEach < TSource > (IEnumerable < TSource > collection,Action < TSource > action)
{
GenericHepler.ForSpecification
< TSource > (collection,action, null );
}
#endregion

#region ForFirstSpecification
/// <summary>
/// ForSpecification对集合中第一个满足predicate条件的元素执行action。如果没有条件,predicate传入null。
/// </summary>
public static void ForFirstSpecification < TSource > (IEnumerable < TSource > collection,Action < TSource > action,Predicate < TSource > predicate)
{
if (predicate == null )
{
foreach (TSourceobj in collection)
{
action(obj);
break ;
}
}
else
{
foreach (TSourceobj in collection)
{
if (predicate(obj))
{
action(obj);
break ;
}
}
}
}
#endregion

有了ForSpecification,我们就可以实现查询方法Where:
#region Where
/// <summary>
/// Where从集合中选取符合条件的元素
/// </summary>
public static IList < TSource > Where < TSource > (IEnumerable < TSource > source,Predicate < TSource > predicate)
{
IList
< TSource > list = new List < TSource > ();
GenericHepler.ForSpecification(source,
delegate (TSourceele){list.Add(ele);},predicate);
return list;
}
#endregion
对于C#3.0中的Select方法,其实现需要匿名类型的支持,而C#2.0中不支持匿名类型,所以,我用泛型来代替。我使用ConvertSpecification来模拟Select实现:
#region ConvertSpecification
/// <summary>
/// ConvertSpecification将source中的符合predicate条件元素转换为TResult类型
/// </summary>
public static IList < TResult > ConvertSpecification < TSource,TResult > (IEnumerable < TSource > source,Func < TSource,TResult > converter,Predicate < TSource > predicate)
{
IList
< TResult > list = new List < TResult > ();
GenericHepler.ForSpecification
< TSource > (source, delegate (TSourceele){list.Add(converter(ele));},predicate);
return list;
}
#endregion
converter委托用于从 TSource类型对象构造TResult类型的对象。
有了ConvertSpecification实现,我们就可以在其上继续实现ConvertAll和ConvertFirstSpecification:
#region ConvertAll
/// <summary>
/// ConvertAll将source中的每个元素转换为TResult类型
/// </summary>
public static IList < TResult > ConvertAll < TSource,TResult > (IEnumerable < TSource > source,Func < TSource,TResult > converter)
{
return GenericHepler.ConvertSpecification < TSource,TResult > (source,converter, null );
}
#endregion

#region ConvertFirstSpecification
/// <summary>
/// ConvertSpecification将source中的符合predicate条件的第一个元素转换为TResult类型
/// </summary>
public static TResultConvertFirstSpecification < TSource,TResult > (IEnumerable < TSource > source,Func < TSource,TResult > converter,Predicate < TSource > predicate)
{
TSourcetarget
= GenericHepler.GetFirstSpecification < TSource > (source,predicate);

if (target == null )
{
return default (TResult);
}

return converter(target);
}
#endregion
有了上面的基础,我们还可以实现ContainsSpecification方法:
#region ContainsSpecification
/// <summary>
/// ContainsSpecification集合中是否包含满足predicate条件的元素。
/// </summary>
public static bool ContainsSpecification < TSource > (IEnumerable < TSource > source,Predicate < TSource > predicate, out TSourcespecification)
{
specification
= default (TSource);
foreach (TSourceelement in source)
{
if (predicate(element))
{
specification
= element;
return true ;
}
}

return false ;
}
#endregion

#region ContainsSpecification
/// <summary>
/// ContainsSpecification集合中是否包含满足predicate条件的元素。
/// </summary>
public static bool ContainsSpecification < TSource > (IEnumerable < TSource > source,Predicate < TSource > predicate)
{
TSourcespecification;
return GenericHepler.ContainsSpecification < TSource > (source,predicate, out specification);
}
#endregion


代码中的注释已经将各个方法的用途说得非常清楚,下面我们举两个例子来看看如何使用它们以发挥它们的威力!
例子一:比如,我们要从当前玩家(IPlayer)列表中找出所有年龄大于30岁的玩家的ID,通常这样做:

public IList < string > GetOldPlayer()
{
IList
< string > results = new List < string > ();
foreach (IPlayerplayer in this .playerList)
{
if (player.Age > 30 )
{
results.Add(player.ID);
}
}

return results;
}

如果使用上面我们封装的API,则可以非常简单地达到目的:

public IList < string > GetOldPlayer()
{
return GenericHepler.ConvertSpecification < IPlayer, string > ( this .playerList, delegate (IPlayerplayer){ return player.ID;}, delegate (IPlayerplayer){ return player.Age > 30 });
}

一句搞定。

例子二:我们要从当前的玩家字典(Dictionary)中取出所有ID不是指定集合中的ID的其它玩家列表。
通常,我们可以这样做:

public IList < IPlayer > GetPartners( params string []excludedUserIDs)
{
IList
< IPlayer > partnersList = new List < IPlayer > ();
foreach ( string userID in this .dicPlayers.Keys)
{
bool exclude = false ;
foreach ( string excludedUser in excludedUserIDs)
{
if (userID == excludedUser)
{
exclude
= true ;
break ;
}
}

if ( ! exclude)
{
partnersList.Add(
this .dicPlayers[userID]);
}
}
return partnersList;
}

使用上面我们封装的API,则非常简单:

public IList < IPlayer > GetPartners( params string []excludedUserIDs)
{
return GenericHepler.Where < IPlayer > ( this .dicPlayers.Values, delegate (IPlayerplayer){ return ! GenericHepler.ContainsSpecification < string > (excludedUserIDs, delegate ( string id){ return id == player.UserID;});});
}

灵活地使用这些API,我们可以非常简洁地操作集合中的元素。
最后给出GenericHepler类的源码下载,其中还包含了几个未介绍的实用的API。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值