链式编程:泛型实现的扩展方法类

序言

本文分享一个用链式编程思想和泛型实现的扩展方法类,用于减少代码量,并提供更为清晰的业务逻辑代码表达。

概念

链式编程:将多个业务逻辑(方法)通过“.”(点号)串联起来的一种代码风格,形似链条,故称链式编程。核心思想在于每个方法均返回自身实例。

泛型:可以理解为是一个类的“篮子“”,只要符合约束的类均可以放置在该“篮子”里面。

扩展方法:向现有类添加方法。

根据泛型和扩展方法的特点,泛型+扩展方法实现了向所有符合约束的“类”添加方法,可减少重复代码量。

(.Net语言提供了这么优雅的特性,刚开始接触确实让我“惊为天人”!这也许是我对它深耕不辍的原因吧!)

 背景

笔者在MES系统的多个模块中,经常要对用户或方法返回值做判断,比如以下判断:

用户输入是否为空或空值;

用户输入的是否为数字或整数;

用户输入的数字是否在正常范围内;

方法返回的是否为True或False;

......

所以便到处充斥着诸如以下的代码:

      if (string.IsNullOrEmpty(txtFullScore.Text))
            {
                MessageBox.Show("满分分数不能为空");
                return;
            }

            if (string.IsNullOrEmpty(txtScore.Text))
            {
                MessageBox.Show("分数不能为空");
                return;
            }

 

作为一个自认为“自我修养”还过得去的程序猿,肯定不允许程序散发“重复代码的气味”,

所以实现了泛型+扩展方法实现的链式编程风格的类。

特点

该类具有以下优点:

  • 该类采用了泛型,可适用于所用引用类型的扩展;
  • 验证结果采用委托方法实现,可实现与平台的解耦;
  • 各扩展方法都返回自身实例,可实现逻辑表达上更为清晰的链式调用

说明

该类主要分两部分:直接传值-扩展方法;委托-扩展方法。

直接传值-扩展方法

验证值的获取方式有两种:直接获取和调用方法获取

方法列表:

  • T IsInt<T>(this T source,string value,Action action
  • T IsNullOrEmpty<T>(this T source, string value, Action action)
  • T IsAllNullOrEmpty<T>(this T source, Action action, params string[] value)
  • T IsNumeric <T>(this T source, string value, Action action)
  • T IsTrue<T>(this T source, bool  IsTrue, Action action)
  • T OPResult<T>(this T source,bool oPResult, Action<bool> action)
  • T Range<T>(this T source, int value, int MinValue, int MaxValue, Action action)

示例代码

方法描述:验证字符串是否为空或空值,验证失败后执行委托。

     /// <summary>
        /// 验证是否为空或空值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">返回实例</param>
        /// <param name="value">验证字符串</param>
        /// <param name="action">验证失败后执行该委托</param>
        /// <returns></returns>
        public static T IsNullOrEmpty<T>(this T source, string value, Action action) where T : class
        {
            if (source == null) return null;
            if (!string.IsNullOrEmpty(value)) return source;
            action();
            return null;
        }

 

委托-扩展方法

 

先判断扩展方法类是否为NULL后才执行委托,避免由于返回的是NULL却仍然执行委托产生报错的情况。

方法列表

  • T IsInt<T>this T source, Func<T, string > value,Action action
  • T IsNullOrEmpty<T>(this T source, Func<T, string > value, Action action)
  • T IsNumeric <T>(this T source, Func<T, string > value, Action action)
  • T IsTrue<T>(this T source, Func<T, bool > value IsTrue, Action action)
  • T OPResult<T>(this T source, Func<T, bool > value oPResult, Action<bool> action)
  • T Range<T>(this T source, Func<T,int> value, int MinValue, int MaxValue, Action action)

示例代码

方法描述:验证委托的返回值是否为空或空值,验证失败后执行委托。

        /// <summary>
        /// 验证是否为空或空值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">返回实例</param>
        /// <param name="value">需验证委托</param>
        /// <param name="action">验证失败后执行该委托</param>
        /// <returns></returns>
        public static T IsNullOrEmpty<T>(this T source, Func<T, string> value, Action action) where T : class
        {
            if (source == null) return null;
            if (!string.IsNullOrEmpty(value(source))) return source;
            action();
            return null;
        }

调用示例

现有一个需求判断分数是否及格,采用WinForm实现。具体需求如下:

满分不能小于60大于100;分数不能小于等于0;当结果大于等于1时,提示PASS,当结果小于1时,提示NG;当输入错误时,需要提示用户。

窗体设计如下图所示:

需求分析

该需求采用如下验证流程:

→满分不能为空

→分数不能为空

→满分必须为整数

→分数必须为整数

→满分必须在60-100之间

→分数不能小于等于0

→计算结果,结果大于等于0.6,提示PASS,否则提示NG。

一般代码写法

            if (string.IsNullOrEmpty(txtFullScore.Text))
            {
                MessageBox.Show("满分分数不能为空");
                return;
            }

            if (string.IsNullOrEmpty(txtScore.Text))
            {
                MessageBox.Show("分数不能为空");
                return;
            }
            int temp = 0;
            if (!int.TryParse(txtFullScore.Text, out temp))
            {
                MessageBox.Show("满分必须为整数");
                return;
            }
            if (!int.TryParse(txtScore.Text, out temp))
            {
                MessageBox.Show("分数必须为整数");
                return;
            }
            if (Convert.ToInt32(txtFullScore.Text)<60||Convert.ToInt32(txtScore.Text)>100)
            {
                MessageBox.Show("满分必须在60-100范围内");
                return;
            }
            if (Convert.ToInt32(txtScore.Text) < 0)
            {
                MessageBox.Show("分数不能小于等于0");
                return;
            }
            if (Calc(Convert.ToInt32(txtFullScore.Text), Convert.ToInt32(txtScore.Text)))
            {
                MessageBox.Show("PASS");
            }
            else
            {
                MessageBox.Show("NG");
            }

 泛型+扩展方法的链式风格写法

            this.IsNullOrEmpty(txtFullScore.Text,()=> MessageBox.Show("满分不能为空"))
                .IsNullOrEmpty(txtScore.Text,()=>MessageBox.Show("分数不能为空"))
                .IsInt(txtFullScore.Text,()=>MessageBox.Show("满分必须为整数"))
                .IsInt(txtScore.Text,()=>MessageBox.Show("分数必须为整数"))
                .Range(t=>Convert.ToInt32(txtFullScore.Text),60,100,()=>MessageBox.Show("满分必须在60-100范围内"))
                .IsTrue(t=>Convert.ToInt32(txtScore.Text)>0,()=>MessageBox.Show("分数不能小于等于0"))
                .OPResult(t=>t.Calc(Convert.ToInt32(txtScore.Text),Convert.ToInt32(txtFullScore.Text)),
                (result)=>{if(result) MessageBox.Show("PASS");else MessageBox.Show("NG");});

 

计算结果Calc的代码如下 

        public bool Calc(int Score, int FullScore)
        {
            return (float)Score / FullScore >= 0.6;
        }

结论

链式风格写法从代码逻辑上看完全与需求流程一致,逻辑表达上更为清晰。

建议

使用Action委托可以自行设定验证通过/不通过时所要进行的操作,如MessageShow,也可写入文件或数据库,或者其他方法,实现解耦。

建议采用工厂方法实现ActionFactory管理所有的Action委托。

 

posted @ 2016-09-27 16:05  蜡笔小黄  阅读(2438)  评论(6编辑  收藏  举报