c# 扩展方法奇思妙用变态篇二:封装 if/else、swith/case 及 while

c# 扩展方法奇思妙用变态篇二:封装 if/else、swith/case 及 while

2009-08-13 18:13 by 鹤冲天, 10284 阅读, 37 评论, 收藏编辑

本文探讨如何使用扩展方法封装 if/else、swith/case及while,通过使用这些扩展,写出的代码将使用很少的大括号{ }。扩展的效果如何,还请大家来评判!
声明:本文属于(改)变(形)态篇,只是提出一种想法,所提供的代码也只是示例,可以测试通过,但不完善。

首先我们来对看if/else和swith/case,两者在代码中都用来表达分支结构。这里我们统一封装成一个If扩展:

复制代码
         public   static  T If < T > ( this  T t, Predicate < T >  predicate, Action < T >  action)  where  T:  class
        {
            
if (t  ==   null throw   new  ArgumentNullException();
            
if  (predicate(t)) action(t);
            
return  t;
        }
复制代码

 看下面的调用代码,生成一个People的实例,让他吃饱喝足休息好再工作:

复制代码
         public   static   void  Test1()
        {
            
// 常规代码
            People people1  =   new  People { Name  =   " ldp615 " , IsHungry  =   true , IsThirsty  =   true , IsTired  =   true  };
            
if  (people1.IsHungry) people1.Eat();
            
if  (people1.IsThirsty) people1.Drink();
            
if  (people1.IsTired) people1.Rest();
            people1.Work();
            
// 使用扩展方法
            People people2  =   new  People { Name  =   " ldp615 " , IsHungry  =   true , IsThirsty  =   true , IsTired  =   true  }
                .If(p 
=>  p.IsHungry, p  =>  p.Eat())
                .If(p 
=>  p.IsThirsty, p  =>  p.Drink())
                .If(p 
=>  p.IsTired, p  =>  p.Rest());
            people2.Work();
        }
复制代码

扩展方法中的If可以使用点“.”链起来,称之“链式编程”,请参见我我随笔《c#链式编程》。
常规代码和使用扩展方法写的代码都在上面,大家比较一下吧。
使用If扩展的代码中用了lambda表达式,如果前面的“p=>p.”能去掉的话,看起来就比较舒服了!编译器通过类型及上下文推演,应该可以做得到吧!
给出People类如下:

People类


对引用类型我们可以使用Action<T>,也以使用链式编程的方式将多个If串起来。
但对值类型来说,就要用Func<T, T>了,每次返回一个新的值 :
         public   static  T If < T > ( this  T t, Predicate < T >  predicate, Func < T, T >  func)  where  T :  struct
        {
            
return  predicate(t)  ?  func(t) : t;
        }
调用代码也要修改:
复制代码
         public   static   void  Test2()
        {
            
// 扩展方式
             int  int0  =   - 121 ;
            
int  int1  =  int0.If(i  =>  i  <   0 , i  =>   - i)
                .If(i 
=>  i  >   100 , i  =>  i  -   100 )
                .If(i 
=>  i  %   2   ==   1 , i  =>  i  -   1 );
            
// 常规方式
             int  int3  =   - 121 ;
            
if  (int3  <   0 ) int3  =   - int3;
            
if  (int3  >   100 ) int3  -=   100 ;
            
if  (int3  %   2   ==   1 ) int3 -- ;
        }
复制代码

引用类型及值类型的扩展我们已经完成,用string来测试一下吧,如下:
复制代码
         public   static   void  Test3()
        {
            
// 从邮箱变换成主页
             string  email  =   " ldp615@163.com " ;
            
string  page  =  email.If(s  =>  s.Contains( " @ " ), s  =>  s.Substring( 0 , s.IndexOf( " @ " )))
                .If(s 
=>!  s.StartsWith( " www. " ), s  =>  s  =   " www. "   +  s)
                .If(s 
=>!  s.EndsWith( " .com " ), s  =>  s  +=   " .com " );
        }
复制代码
但编译不通过,会提示错误:

这个错误比较怪,我们写了两个扩展,一个是给值类型的,一个给引用类型,可string类型在这里都不行。这个原因我说不清楚了,还留给园子里高手们吧。
不过专门为string写个扩展,这个问题可以化解,如下:
         public   static   string  If( this   string  s, Predicate < string >  predicate, Func < string string >  func)
        {
            
return  predicate(s)  ?  func(s) : s;
        }
看来扩展方法也是有优先级的:对同一个类进行多次扩展,扩展方法相名,参数也等效(数量、顺序相同),非泛版扩展要比泛型版扩展优先级高。

下面再来看一段swith代码,很啰嗦的!这里是为了引出扩展硬写出来的:
复制代码
         public   static   void  Test4()
        {
            
string  englishName  =   " apple " ;
            
string  chineseName  =   string .Empty;
            
switch  (englishName)
            {
                
case   " apple " :
                    chineseName 
=   " 苹果 " ;
                    
return ;
                
case   " orange " :
                    chineseName 
=   " 桔子 " ;
                    
return ;
                
case   " banana " :
                    chineseName 
=   " 香蕉 " ;
                    
return ;
                
case   " pear " :
                    chineseName 
=   " " ;
                    
break ;
                
default :
                    chineseName 
=   " 未知 " ;
                    
break ;
            }
            Console.WriteLine(chineseName);
        }
复制代码
我们把这种方式用扩展方法来完成:
复制代码
         public   static   TOutput Switch < TOutput, TInput > ( this  TInput input, IEnumerable < TInput >  inputSource, IEnumerable < TOutput >  outputSource, TOutput defaultOutput)
        {
            IEnumerator
< TInput >  inputIterator  =  inputSource.GetEnumerator();
            IEnumerator
< TOutput >  outputIterator  =  outputSource.GetEnumerator();

            TOutput result 
=  defaultOutput;
            
while  (inputIterator.MoveNext())
            {
                
if  (outputIterator.MoveNext())
                {
                    
if  (input.Equals(inputIterator.Current))
                    {
                        result 
=  outputIterator.Current;
                        
break ;
                    }
                }
                
else   break ;
            }
            
return  result;
        }
复制代码
下面的Test5是调用:
复制代码
         public   static   void  Test5()
        {
            
string  englishName  =   " apple " ;
            
string  chineseName  =  englishName.Switch(
                
new   string [] {  " apple " " orange " " banana " " pear "  },
                
new   string [] {  " 苹果 " " 桔子 " " 香蕉 " " "  },
                
" 未知 "
                );
            Console.WriteLine(chineseName);
        }
复制代码
简单清晰明了!

最后是一个对while的扩展封装:
         public   static   void  While < T > ( this  T t,  Predicate < T >  predicate, Action < T >  action)  where  T:  class
        {
            
while  (predicate(t)) action(t);
        }
调用代码:
复制代码
         public   static   void  Test6()
        {
            People people 
=   new  People { Name  =   " Wretch "  };
            people.While(
                p 
=>  p.WorkCount  <   7 ,
                p 
=>  p.Work()
                    );
            people.Rest();
        }
复制代码
这里又“召唤”了一个人,不让吃喝不让休息,连续工作7次...
这while扩展中只能执行一个Action<T>,不太好,我们用params改进一下:
复制代码
         public   static   void  While < T > ( this  T t, Predicate < T >  predicate,  params  Action < T > [] actions)  where  T :  class
        {
            
while  (predicate(t))
            {
                
foreach  (var action  in  actions)
                    action(t);
            }
        }
复制代码
再来调用,可以在循环中执行多个操作了,这次舒服工作完吃饭喝水休息,再来工作...
复制代码
         public   static   void  Test7()
        {
            People people 
=   new  People { Name  =   " Wretch "  };
            people.While(
                p 
=>  p.WorkCount  <   7 ,
                p 
=>  p.Work(),
                p 
=>  p.Eat(),
                p 
=>  p.Drink(),
                p 
=>  p.Rest()
                    );
            people.Rest();
        }
复制代码
当然前面的If也可以这样的,这里只写出一个:
If改进
不使用 params,你就要显示声明一个Action<T>的集合了!关于params, 在我的随笔《 改进 Scottgu 的 "In" 扩展 》有说明。

本人系列文章《 c#扩展方法奇思妙用》,敬请关注!

-------------------

思想火花,照亮世界

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值