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);
                            }
                        }
                    }
                }
            }
            if (data.UT_040 != null)
            {
                var dataObj = data.UT_040;
                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_041 != null)
            {
                var dataObj = data.UT_041;
                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_042 != null)
            {
                var dataObj = data.UT_042;
                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);
                }
            }
            if (data.UT_040 != null)
            {
                var dataObj = data.UT_040;
                string checkResult = CheckSingleFieldNull(dataObj, shownFields);
                if (checkResult.Length > 0)
                {
                    result.Add(checkResult);
                }
            }
            if (data.UT_041 != null)
            {
                var dataObj = data.UT_041;
                string checkResult = CheckSingleFieldNull(dataObj, shownFields);
                if (checkResult.Length > 0)
                {
                    result.Add(checkResult);
                }
            }
            if (data.UT_042 != null)
            {
                var dataObj = data.UT_042;
                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 Ts = data.GetType();
            for (var i = 0; i < shownFields.Count; i++)
            {
                var tn = shownFields[i].code.CODEVALUE;
                dynamic fv = Ts.GetProperty(tn).GetValue(data, null);
                if (fv == null)
                {
                    result.Add(shownFields[i].code.CODENAME);
                    continue;
                }
                string checkResult = CheckSingleFieldNull(fv, 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;
        }

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

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

时间: 2024-11-09 11:12:42

C#中Dynamic的妙用及代码重构的相关文章

【转】C#中dynamic的正确用法

原文:http://www.cnblogs.com/qiuweiguo/archive/2011/08/03/2125982.html dynamic是FrameWork4.0的新特性.dynamic的出现让C#具有了弱语言类型的特性.编译器在编译的时候不再对类型进行检查,编译期默认dynamic对象支持你想要的任何特性.比如,即使你对GetDynamicObject方法返回的对象一无所知,你也可以像如下那样进行代码的调用,编译器不会报错: dynamic dynamicObject = Get

C#中dynamic的正确用法 以及 typeof(DynamicSample).GetMethod(&quot;Add&quot;);

dynamic是FrameWork4.0的新特性.dynamic的出现让C#具有了弱语言类型的特性.编译器在编译的时候不再对类型进行检查,编译期默认dynamic对象支持你想要的任何特性.比如,即使你对GetDynamicObject方法返回的对象一无所知,你也可以像如下那样进行代码的调用,编译器不会报错: dynamic dynamicObject = GetDynamicObject(); Console.WriteLine(dynamicObject.Name); Console.Writ

C#中dynamic的正确用法

dynamic是FrameWork4.0的新特性.dynamic的出现让C#具有了弱语言类型的特性.编译器在编译的时候不再对类型进行检查,编译期默认dynamic对象支持你想要的任何特性.比如,即使你对GetDynamicObject方法返回的对象一无所知,你也可以像如下那样进行代码的调用,编译器不会报错: dynamic dynamicObject = GetDynamicObject();Console.WriteLine(dynamicObject.Name);Console.WriteL

改善C#程序的建议2:C#中dynamic的正确用法

原文:改善C#程序的建议2:C#中dynamic的正确用法 dynamic是FrameWork4.0的新特性.dynamic的出现让C#具有了弱语言类型的特性.编译器在编译的时候不再对类型进行检查,编译期默认dynamic对象支持你想要的任何特性.比如,即使你对GetDynamicObject方法返回的对象一无所知,你也可以像如下那样进行代码的调用,编译器不会报错: dynamic dynamicObject = GetDynamicObject(); Console.WriteLine(dyn

编程算法 - 数组中出现次数超过一半的数字 代码(C)

数组中出现次数超过一半的数字 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 数组中有一个数字出现的次数超过数组长度的一半, 请找出这个数字. 1. 使用高速排序(QuickSort)的方法, 把中值(middle)和索引(index)匹配, 输出中值, 并检測是否符合要求. 2. 使用计数方法依次比較. 代码:  方法1: /* * main.cpp * * Created on: 2014.6.12 * Author: Spike */

JQuery中trim函数的具体实现代码

由于Javascript 1.8.1 之前的版本,没有内置 trim 函数,所以 JQuery 对它有自己的实现.不同的JQuery版本,trim函数的实现也不尽相同. 阅读本文需要掌握正则表达式用法,如果不是很了解,建议阅读这个.鉴于正则表达式的强大用途(在各种语言如JS,Python,Ruby,Java中都会用到),建议重点学习并掌握. JQuery 1.7.2版本 // 截取的部分源码,不是完整语句,旨在说明实现过程 trimLeft = /^\s+/, trimRight = /\s+$

检测字符串中是否含有非法字符js代码

检测字符串中是否含有非法字符js代码:通常情况下,网站输入的字符串内容是需要经过检测的,因为有些字符带有一定的危险性,会对站点带来一定的危害,下面就介绍一下如何检测一个字符串是否含有非法字符,代码如下: function checks(str){ szMsg="[#_%&'\",;:=!^]"; alertStr=""; for(i=1;i<szMsg.length+1;i++){ if(str.indexOf(szMsg.substring

.Net Web产品中增加自己的功能和代码?

背景: 最近有一个项目,一个朋友找了一个网上比较成熟的CMS系统(动易),让我给他增加一些功能,这个产品功能挺多,但是没有源代码.按照以前的做法,就是直接反编译他的dll,生成源代码,然后在源代码的基础上修改和完善自己的功能.但是研究了一下这个产品,bin下面的DLL非常多,有主要的,还有辅助的.如果每个dll都反编译,简直不现实. ? 用发编译工具?ILSpy打开里面几个主要的dll,发现还加壳混淆了,用De4Dot反混淆出来.里面的代码还是非常清晰,但是如果每个dll都这样搞,岂不累死. ?

Switch Case语句中多个值匹配同一个代码块的写法

switch ($p) { case 'home': case '': $current_home = 'current'; break; case 'users.online': case 'users.location': case 'users.featured': case 'users.new': case 'users.browse': case 'users.search': case 'users.staff': $current_users = 'current'; break