• C#中Dynamic的妙用及代码重构


    应用场景:检查几个表的特定字段是否为空,字段是否为空是在数据库中进行配置的。前台根据数据中字段的设置,进行动态检查。

    原始人版:

            private string CheckFieldNull(MONTHINPUTDATA data,IList<ReportTemplate> shownFields)
            {
                IList<string> result = new List<string>();
                if (data.UT_003 != null)
                {
                    var dataObj = data.UT_003;
                    for (var i = 0; i < shownFields.Count; i++)
                    {
                        var objName = dataObj.ToString().Substring(dataObj.ToString().LastIndexOf('.') + 1);
                        if (shownFields[i].code.CODEVALUE.Replace("_","") == objName)
                        {
                            var fs = shownFields[i].FieldList;
                            Type Ts = dataObj.GetType();
                            for (var j = 0; j < fs.Count; j++)
                            {
                                object o = Ts.GetProperty(fs[j].FIELDNO).GetValue(dataObj, null);
                                if (o == null)
                                {
                                    result.Add(fs[j].FIELDNAME);
                                }
                            }
                        }
                    }
                }
                if (data.UT_012 != null)
                {
                    var dataObj = data.UT_012;
                    for (var i = 0; i < shownFields.Count; i++)
                    {
                        var objName = dataObj.ToString().Substring(dataObj.ToString().LastIndexOf('.') + 1);
                        if (shownFields[i].code.CODEVALUE.Replace("_", "") == objName)
                        {
                            var fs = shownFields[i].FieldList;
                            Type Ts = dataObj.GetType();
                            for (var j = 0; j < fs.Count; j++)
                            {
                                object o = Ts.GetProperty(fs[j].FIELDNO).GetValue(dataObj, null);
                                if (o == null)
                                {
                                    result.Add(fs[j].FIELDNAME);
                                }
                            }
                        }
                    }
                }
                return string.Join(",",result);
            }

    这样的代码确实让人纠结。的确,开发者可以几乎不用动脑子,以比较快速度编码(完成一段后,复制、粘贴即可搞定),完成任务。这种编码有一定的灵活性,具体来说就是检查的字段设置(字段由需要检查,变更为不需要检查或者相反)修改后,代码不用变就可以满足要求。不足之处在于有大量的重复代码,而且还应用了硬编码。假如又增加了需要判断的字段表,那么此方法必须修改才行。而且这种写法的代码量很大,也不利于后期维护。总体来说这样的代码质量比较差劲。

    OK,既然C# 4.0引入了dynamic,那么我们不妨用此技术简化下代码,于是,就有了第二版的代码,代码如下:

            private string CheckFieldNull(MONTHINPUTDATA data,IList<ReportTemplate> shownFields)
            {
                IList<string> result = new List<string>();
                if (data.UT_003 != null)
                {
                    var dataObj = data.UT_003;
                    string checkResult = CheckSingleFieldNull(dataObj, shownFields);
                    if (checkResult.Length > 0)
                    {
                        result.Add(checkResult);
                    }
                }
                if (data.UT_012 != null)
                {
                    var dataObj = data.UT_012;
                    string checkResult = CheckSingleFieldNull(dataObj, shownFields);
                    if (checkResult.Length > 0)
                    {
                        result.Add(checkResult);
                    }
                }
                return string.Join(",",result);
            }
    
    
            private string CheckSingleFieldNull(dynamic dataObj, IList<ReportTemplate> shownFields)
            {
                for (var i = 0; i < shownFields.Count; i++)
                {
                    var objName = dataObj.ToString().Substring(dataObj.ToString().LastIndexOf('.') + 1);
                    if (shownFields[i].code.CODEVALUE.Replace("_", "") == objName)
                    {
                        var fs = shownFields[i].FieldList;
                        Type Ts = dataObj.GetType();
                        for (var j = 0; j < fs.Count; j++)
                        {
                            object fv = Ts.GetProperty(fs[j].FIELDNO).GetValue(dataObj, null);
                            if (fv == null)
                            {
                                return fs[j].FIELDNAME;
                            }
                        }
                    }
                }
                return string.Empty;
            }

    这样一来,将检查部分抽出来,提炼成一个函数,需要判断的地方进行判断,这样修改下来,代码确实精简了很多,但是....,似乎代码量还是很大,并且还没有解决硬编码(枚举表名)的问题。既然我们是冲着dynamic去的,那么我们不妨再做的彻底些,于是第三版趁着热乎劲出炉了。

            private string CheckFieldNull(MONTHINPUTDATA data, IList<ReportTemplate> shownFields)
            {
                IList<string> result = new List<string>();
                Type inputDataType = data.GetType();
                for (var i = 0; i < shownFields.Count; i++)
                {
                    var fieldNo = shownFields[i].code.CODEVALUE;
    
                    dynamic fieldValue = inputDataType.GetProperty(fieldNo).GetValue(data, null);
                   
                    if (fieldValue == null)
                    {
                        result.Add(shownFields[i].code.CODENAME);
                        continue;
                    }
    
                    string checkResult = CheckSingleTableFieldNull(fieldValue, shownFields[i].FieldList);
                    
                    if (checkResult.Length > 0)
                    {
                        result.Add(checkResult);
                    }
                }
                return string.Join("", result);
            }
            
            private string CheckSingleTableFieldNull(dynamic field, IList<UVQYJYPERIODREPORT> shownFields)
            {
                Type inputDataType = field.GetType();
    
                IList<string> result = new List<string>();
    
                for (var i = 0; i < shownFields.Count; i++)
                {
                    //字段为目录级别时,不需要判断。
                    if (shownFields[i].ISDIRECTORY == field_IsDirectory) { continue; }
    
                    object fieldValue = inputDataType.GetProperty(shownFields[i].FIELDNO).GetValue(field, null);
    
                    if (fieldValue == null)
                    {
                        result.Add(shownFields[i].FIELDNAME);
                    }
                }
                return string.Join("", result);
            }

    这样一来,完全达到了动态检查字段为空的目的,不再硬编码,完全听命于数据库中有关字段的配置。至此,再无纷扰,天下太平了。

    备注:请无视示例代码中函数的参数命名及函数内变量的命名方式(纯粹展示用)。

  • 相关阅读:
    如何使用websocket实现前后端通信
    影响MySQL的性能(一)磁盘的选择
    springboot结合日志门面SLF4j和日志实现Logback的使用
    分享一个猜数字小游戏的脚本
    关于drop table *** purge (drop后不过回收站)
    关于DateBase link(dbLINK)及同义词
    关于数据更新(update)
    关于insert into(插入值)
    关于wm_concat(把一列的值,通过','进行分隔后,合并成一个值进行显示)
    关于PIVOT(用于行转列)
  • 原文地址:https://www.cnblogs.com/jizhong/p/4158425.html
Copyright © 2020-2023  润新知