这几天研究了一下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 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)
        {www.elivn.com
            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。

转载于:https://www.cnblogs.com/seoxs/archive/2011/04/20/2021838.html

【C#2.0】发挥匿名委托的威力!相关推荐

  1. 用一个实例说说委托,匿名委托,Lamda表达式

    C#到3.0中一直都在不断地提高,增加了很多特性,从2.0的匿名委托到现在的LAMDA表达式,为的就是让大家觉得语言越来越人性化.以下是我写的一个小DEMO,用来简单示例一下他们之间的关系.非常简单易 ...

  2. Delegate,Action,Func,匿名方法,匿名委托,事件

    一.委托Delegate 一般的方法(Method)中,我们的参数总是string,int,DateTime...这些基本的数据类型(或者没有参数),比如 [c-sharp] view plainco ...

  3. Delegate,Action,Func,匿名方法,匿名委托,事件 (转载)

    Delegate,Action,Func,匿名方法,匿名委托,事件 (转载) 一.委托Delegate 一般的方法(Method)中,我们的参数总是string,int,DateTime...这些基本 ...

  4. C# 匿名委托、匿名方法、匿名对象、Lambda表达式

    C# 匿名委托.匿名方法.匿名对象.Lambda表达式 原文:C# 匿名委托.匿名方法.匿名对象.Lambda表达式 一.匿名类型 可通过使用 new 运算符和对象初始值创建匿名类型. 示例: var ...

  5. C#多线程|匿名委托传参数|测试您的网站能承受的压力|附源代码

    源代码下载:http://www.sufeinet.com/thread-13-1-1.html 引言 我们一直在做网站,但在我河南这块,对测试工作,特别是压力测试一般都不怎么在意,都是自己访问一下速 ...

  6. unity3d C#用匿名委托循环注册按钮点击事件报错:索引超界 ArgumentOutOfRangeException: Index was out of range. Must be non-ne

    unity3d C#用匿名委托循环注册按钮点击事件报错:索引超界 ArgumentOutOfRangeException: Index was out of range. Must be non-ne ...

  7. C#委托,多播委托,匿名委托,事件

    委托 委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递.事件是一种特殊的委托. 委托是方法的抽象,它存储的就是一系列具有相同签名和返回类型的方法的地址.调用委托的时候,委 ...

  8. 分配委托、匿名委托、委托

    分配委托(将命名方法分配给其委托) using System;public class GenericFunc {public static void Main(){// Instantiate de ...

  9. NEXT社区小课堂 | 第四课:dBFT 2.0详解 | 委托拜占庭容错:技术细节、挑战和前景...

    NEXT社区 | 小课堂 由于近期NEXT社区加入很多新的小伙伴,有在校大学生,有对区块链感兴趣的传统企业从业者.为了更方便.更系统的让NEXT社区的伙伴们了解NEO的技术知识,因此我们开设了小课堂, ...

最新文章

  1. jQuery的attr方法处理checkbox的问题
  2. Android--Matrix图片变换处理
  3. 2021的第二封拒信,来自斯坦福电气工程
  4. Rancher2.0中邮件通知的设置
  5. 深入浅出 Linux 惊群:现象、原因和解决方案
  6. (一)导学(Javascript设计模式系统讲解与应用)
  7. NA-NP-IE系列实验5:配置文件的备份和IOS 的备份
  8. linux增加 inode空间,linux 增加inode 的方法
  9. sigmoid激活函数
  10. 使用公开页实现扫码签到功能
  11. Google 应用与游戏出海 4 月刊: 带您连线 GDC,赢在发布前!
  12. Java小白 前端后端开发 环境搭建【jdk+idea+webstorm+maven+nodejs+vue+mysql】
  13. 怎么验证mysql安装成功_mysql如何验证是否安装成功
  14. 响应式网站如何实现?
  15. vmware虚拟机无法u盘启动的解决办法
  16. java.sql.SQLException: Unable to load authentication plugin ‘caching_sha2_password‘.
  17. 网络安全--入侵攻击类型
  18. 修复计算机黑屏,笔记本电脑黑屏怎么修复 笔记本电脑黑屏修复方法【详解】...
  19. OMRON E6B2-CWZ6C
  20. 公交卡非法充值与其计费系统之分析

热门文章

  1. 《计算机导论》课程论文,计算机导论课程论文
  2. js清空文本框的值_一个Vue.js实例控制字变大变小,含样式操作,flex布局。「603」...
  3. imgaug批量椒盐噪声 python_python图像扩增-imgaug
  4. ubuntu安装python_Linux下的Python开发配置鸭
  5. 基于Java+SpringBoot+vue+element等动物救助平台设计和实现
  6. java打印等腰梯形
  7. java 堆排序方式_幾種排序方式的java實現(02:希爾排序,歸並排序,堆排序)
  8. mysql无法启动修复_记一次MySQL无法启动及修复经历
  9. C++ auto和decltype关键字
  10. int mysql_「MYSQL」MYSQL中的int(11)到底代表什么意思?