【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  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。

你可能感兴趣的:(C#)