首页 > 代码库 > C#中Dynamic的妙用及代码重构

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;        }

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

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

 

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