• 数据模型类对比,用反射做个快乐的程序员


      曾经看《大话设计模式》的时候说到 反射反射程序员的欢乐,当时我还不太相信 毕竟自己不太会反射。甚至什么时候用反射我也不太知道,只能说查了些资料知道有一些反射这咱东西仅此而已。

      这几天在做一个人才管理系统,其中有一个让我纠结的就是 操作日志这块吧,特别是在修改的时候要记录每个字段改变前后的情况。好吧,当时有两个决定方案吧。一、再建了一张和原表相同的结构的呗,再用一个外键和原表主键连下,做下记录吧。二、就是在读取数据的时候存储两个Model,一个New Model 一个Old Model呗,然后再对比下。

      最后,由于种种的原因选择了第二次方式。好吧,竟然用第二种说出来一个问题,怎么对比两个Model来,难道一个个字段对比吗?天哪这不噩梦嘛,如果有20个字段我不是要写20多个对比 20多个IF了,这我不干 这明显就不是最良的代码好,不过我也没什么好的办法 只能问问度娘、GOOOGLE呗,在这个互联网的时代,要善用搜索引擎嘛,于是找了下。

    一开始代码应该是这样的。有两个实体变量,存放的是修改前和修改后的信息。比如:

    InfoModel oldModel=new InfoModel();
    
    InfoModel newModel=new InfoModel();

    需要遍历这两个实体类的全部属性的值来进行对比,并将有差别的列出来。

      找到一个解决的方案就是使用反射进行对比

    //反射遍历
    System.Reflection.PropertyInfo[] mPi = typeof(InfoModel).GetProperties();
    
    
                    for (int i = 0; i < mPi.Length; i++)
                    {
                        System.Reflection.PropertyInfo pi = mPi[i];
    
                        oldValue = pi.GetValue(oldModel, null).ToString();
                        newValue = pi.GetValue(newModel, null).ToString();
                        if (oldValue !=newValue )
                        {
                             有差别的列出来
                        }
                     }
    
    }
    View Code

      在这里,用一个小问题那就是typeOf是用来放是哪个 MODEL的嘛!还有就是这是什么 oldModel,newModel,如果向这么不就写死了嘛,每比较一个数据模型类不是都要这样写一个方法不是很麻烦,这以前那个对比虽然好了些不会用这么多的IF了 可是还是不能复用的嘛,只知道做软件设计的做到啥 可维护、可复用、可扩展、灵活性好。

       好吧,这个明显不能复用的嘛。改改呗,最好做到的就是所有的类都可以用这个方法,此时脑子里瞬间就想起了 泛型。【泛型类和泛型方法同时具备可重用性、类型安全和效率,这是非泛型类和非泛型方法无法具备的。 泛型通常用与集合以及作用于集合的方法一起使用。 .NET Framework 2.0 版类库提供一个新的命名空间 System.Collections.Generic,其中包含几个新的基于泛型的集合类。泛型是 C# 2.0 的最强大的功能。通过泛型可以定义类型安全的数据结构,而无须使用实际的数据类型。这能够显著提高性能并得到更高质量的代码,因为您可以重用数据处理算法,而无须复制类型特定的代码。在概念上,泛型类似于 C++ 模板,但是在实现和功能方面存在明显差异。】这是从MSDN对泛型的介绍,好吧,我想这个功能应该可以满足我的要求,把代码改改呗

     1   public string CompareModel<T>(T newModel, T oldModel)  
     2         {
     3             StringBuilder strLog = new StringBuilder();
     4             System.Reflection.PropertyInfo[] mPi = typeof(T).GetProperties();
     5             for (int i = 0; i < mPi.Length; i++)
     6             {
     7                 System.Reflection.PropertyInfo pi = mPi[i];
     8                 string strName = string.Empty;
     9                 string log = string.Empty;
    10                 if (pi.GetValue(oldModel, null) != null && pi.GetValue(newModel, null) != null)
    11                 {
    12                     string name = pi.Name;//字段名
    13                     string oldValue = pi.GetValue(oldModel, null).ToString();//获取对应字段的值
    14                     string newValue = pi.GetValue(newModel, null).ToString();
    15                     if (oldValue != newValue)
    16                     {//具体差异的操作
    17                         strLog.AppendFormat("{0}从{1}改为{2}", name, oldValue, newValue);
    18                     }
    19                 }
    20             }
    21             return strLog.ToString();
    22         }
    View Code

      这样也可以一一的不同的数据列出来了,可这里还有一个问题就是其中的NAME是英文的啊,总不可能给客户看英文的吧,再想想办法呗。在这里看到 PropertyInfo 有个GetCustomAttributes 的方面,这不就是可以获取特性的方法嘛,特性我知道就啊,就想在MVC中Model类里的字段上前的 [Display(Name = "用户名")] 这种东东嘛,好吧,我也有这个样的吧,虽然Attributes 是可以自定义的,但我还是小小的懒下使用MVC里的算了,自己写也太麻烦,自己本身对这个也不太会用嘛,只能算是拿来主义。开心的引用了using System.ComponentModel.DataAnnotations;

     1 using System;
     2 using System.ComponentModel.DataAnnotations;
     3 
     4  public class LoginModel
     5     {
     6        
     7         [Display(Name = "用户名")]
     8         public string UserName { get; set; }
     9 
    10         public string ExternalLoginData { get; set; }
    11     }
    12  /// <summary>
    13         /// 说明:对比实体类
    14         /// 时间:2014年2月20日 14:17:48
    15         /// Auhter:Kim
    16         /// </summary>
    17         /// <typeparam name="T"></typeparam>
    18         /// <param name="newModel"></param>
    19         /// <param name="oldModel"></param>
    20         /// <returns></returns>
    21         public string CompareModel<T>(T newModel, T oldModel) where T : class,new ()
    22         {
    23             StringBuilder strLog = new StringBuilder();
    24             System.Reflection. PropertyInfo[] mPi = typeof(T).GetProperties();
    25             for (int i = 0; i < mPi.Length; i++)
    26             {
    27                 System.Reflection. PropertyInfo pi = mPi[i];
    28                 string strName = string .Empty;
    29                 string log=string .Empty;
    30                 if (pi.GetValue(oldModel, null ) != null && pi.GetValue(newModel, null ) != null)
    31                 {
    32 
    33                     strName = Attributes.GetDisplayInfo<T>(pi.Name);
    34                     string oldValue = pi.GetValue(oldModel, null).ToString();
    35                     string newValue = pi.GetValue(newModel, null).ToString();
    36                     if (oldValue != newValue)
    37                     {
    38                         if (GetNameByDictonary(strName, oldValue, newValue, out log))
    39                             strLog.Append(log);
    40                         else
    41                             strLog.AppendFormat("<strong>{0}</strong><span>{0} 从 {1} 改为 {2}</span>&nbsp;&nbsp;", strName, oldValue, newValue);
    42                     }
    43                 }
    44             }
    45             return strLog.ToString();
    46         }
    47 
    48 
    49 /// <summary>
    50         /// 获取DisplayInfo
    51         /// </summary>
    52         /// <param name="t"></param>
    53         public static string GetDisplayInfo<T>( string name) where T : class,new ()
    54         {
    55             Type objType = typeof (T);
    56             // Using reflection.
    57             string strName = string .Empty;
    58             PropertyInfo propInfo = objType.GetProperty(name);
    59             object[] attrs = propInfo.GetCustomAttributes(typeof (DisplayAttribute), true);  // Reflection.
    60             // Displaying output.
    61             if (attrs.Length > 0)
    62             {
    63                 DisplayAttribute a = attrs[0] as DisplayAttribute;
    64                 strName = a.Name;
    65             }
    66 
    67             return strName;
    68         }
    View Code

    这样的代码也基本的符合要求了,不过小弟在这还有一个不解的地方就是说,有一些数据实体类型的字段是别的表的外键嘛,这又要怎么正常在的数据显示出来哪?希望各位大神 指导一二,各位码农、码友们有些好的解决方案 也探讨下呗,提出你们的宝贵意见,小弟先在这里谢过了!  

                                                  

  • 相关阅读:
    未在本地计算机上注册“Microsoft.Jet.OleDb.4.0”提供程序
    GridView选中行变色
    GridView 添加/删除行
    Session、Cookie、Application、ViewState和Cache 这四者的区别
    后台动态给textbox的字体颜色赋值
    JS来判断文本框内容改变事件
    gridview JS控件赋值后如何取值
    c#如何把8位字符串转换成日期格式
    从今天起,热爱生活
    杂得得杂
  • 原文地址:https://www.cnblogs.com/chenmoit/p/3561922.html
Copyright © 2020-2023  润新知