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


    序言

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

    概念

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

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

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

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

    (.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委托。

  • 相关阅读:
    正则表达式的点星匹配
    好玩Python——PIL项目实训(四)
    mysql中正则表达式使用学习记录
    linux下每个目录文件的作用
    彻底搞懂Android文件存储---内部存储,外部存储以及各种存储路径解惑
    获取APP包名和ACtivity名的方法
    mysql 中 王数据表中插入中文字段报错:mysql> insert into a values(202,"王一"); ERROR 1366 (HY000): Incorrect string value: 'xE7x8Ex8BxE4xB8x80' for column 'tname' at row 1
    linux系统下安装mysql
    测试人员初步分析BUG原因--转载
    PC端通过ADB命令 无线向 andriod端发送文件
  • 原文地址:https://www.cnblogs.com/huangmianwu/p/5913200.html
Copyright © 2020-2023  润新知