C#发挥匿名委托的威力
2011-06-24 09:56
92 查看
这几天研究了一下Linq,C#
3.0中的“扩展方法”特性为IEnumerable<T>增加了诸如Where、Select等查询方法,这使得“语言集成查询”成为顺其
自然的事情。而C#3.0中Linq的实现也是建立在C#2.0的匿名委托的特性之上。
今天,我尝试在C#2.0中使用匿名委托模拟C#3.0中Where、Select等查询方法的实现。我将所有的查询方法作为静态方法在GenericHepler静态类中实现。
之前,我们先定义泛型委托:
这个委托在后面的实现中需要用到。
作为基础,首先,我们需要实现ForSpecification方法,该方法的含义是:对集合中满足指定条件的元素执行指定方法调用。
有了ForSpecification的实现,我们就可以在其基础上实现ForEach和ForFirstSpecification:
有了ForSpecification,我们就可以实现查询方法Where:
对于C#3.0中的Select方法,其实现需要匿名类型的支持,而C#2.0中不支持匿名类型,所以,我用泛型来代替。我使用ConvertSpecification来模拟Select实现:
converter委托用于从TSource类型对象构造TResult类型的对象。
有了ConvertSpecification实现,我们就可以在其上继续实现ConvertAll和ConvertFirstSpecification:
有了上面的基础,我们还可以实现ContainsSpecification方法:
代码中的注释已经将各个方法的用途说得非常清楚,下面我们举两个例子来看看如何使用它们以发挥它们的威力!
例子一:比如,我们要从当前玩家(IPlayer)列表中找出所有年龄大于30岁的玩家的ID,通常这样做:
如果使用上面我们封装的API,则可以非常简单地达到目的:
一句搞定。
例子二:我们要从当前的玩家字典(Dictionary)中取出所有ID不是指定集合中的ID的其它玩家列表。
通常,我们可以这样做:
使用上面我们封装的API,则非常简单:
灵活地使用这些API,我们可以非常简洁地操作集合中的元素。
最后给出GenericHepler类的源码下载,其中还包含了几个未介绍的实用的API。files.cnblogs.com/zhuweisky/GenericHepler.rar
3.0中的“扩展方法”特性为IEnumerable<T>增加了诸如Where、Select等查询方法,这使得“语言集成查询”成为顺其
自然的事情。而C#3.0中Linq的实现也是建立在C#2.0的匿名委托的特性之上。
今天,我尝试在C#2.0中使用匿名委托模拟C#3.0中Where、Select等查询方法的实现。我将所有的查询方法作为静态方法在GenericHepler静态类中实现。
之前,我们先定义泛型委托:
public delegate TResult Func<T, TResult>(T source);
这个委托在后面的实现中需要用到。
作为基础,首先,我们需要实现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 (TSource obj in collection) { action(obj); } return; } foreach (TSource obj 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 (TSource obj in collection) { action(obj); break; } } else { foreach (TSource obj 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(TSource ele) { 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(TSource ele) { 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 TResult ConvertFirstSpecification<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, TResult> converter, Predicate<TSource> predicate) { TSource target = 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 TSource specification) { specification = default(TSource); foreach (TSource element 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) { TSource specification; return GenericHepler.ContainsSpecification<TSource>(source, predicate, out specification); } #endregion
代码中的注释已经将各个方法的用途说得非常清楚,下面我们举两个例子来看看如何使用它们以发挥它们的威力!
例子一:比如,我们要从当前玩家(IPlayer)列表中找出所有年龄大于30岁的玩家的ID,通常这样做:
public IList<string> GetOldPlayer() { IList<string> results = new List<string>(); foreach (IPlayer player 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(IPlayer player) { return player.ID; } , delegate(IPlayer player) {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(IPlayer player) { return !GenericHepler.ContainsSpecification<string>(excludedUserIDs, delegate(string id) { return id == player.UserID; }); }); }
灵活地使用这些API,我们可以非常简洁地操作集合中的元素。
最后给出GenericHepler类的源码下载,其中还包含了几个未介绍的实用的API。files.cnblogs.com/zhuweisky/GenericHepler.rar
相关文章推荐
- 【C#2.0】发挥匿名委托的威力!
- 【C#2.0】发挥匿名委托的威力!
- 【C#2.0】发挥匿名委托的威力!
- C#中的委托,匿名方法和Lambda表达式
- C#匿名方法增加、删除委托
- C# - 委托_ 匿名方法
- c# 匿名方法(委托)
- C#2.0 匿名委托
- 编写高质量代码改善C#程序的157个建议[为泛型指定初始值、使用委托声明、使用Lambda替代方法和匿名方法]
- C#的委托,匿名方法和Lambda表达式
- c#打包文件解压缩 C#中使用委托、接口、匿名方法、泛型委托实现加减乘除算法 一个简单例子理解C#的协变和逆变 对于过长字符串的大小比对
- 编写高质量代码改善C#程序的157个建议[为泛型指定初始值、使用委托声明、使用Lambda替代方法和匿名方法]
- C#2.0 匿名委托
- C# 委托 事件 匿名方法
- c# 多播委托 和匿名方法
- C#中分别对委托、匿名方法、Lambda表达式、Lambda表达式树以及反射执行同一方法的过程进行比较。
- C#学习之初步理解委托、事件、匿名方法和Lambda
- C#委托的妙文,让你知道如何发挥委托的作用
- C#2.0中委托与匿名委托-引
- C#中的委托,匿名方法和Lambda表达式