zoukankan      html  css  js  c++  java
  • C# 通过反射实现对象映射:将2个属性相近的对象相互转换

    前言

    我们在编程过程中,经常需要将一个对象转成另一个对象(一般称为对象映射)。
    比如我们有2个类:

    //第1个类 CLS1
    class CLS1
    {
        public int i {get; set;}
    	public string str {get; set;}
    }
    //第2个类 CLS2
    class CLS2
    {
        public int i {get; set;}
    	public string str {get; set;}
    }
    

    两个类都拥有属性 istr
    当我们需要将 CLS1 的实例对象转化为 CLS2 的实例对象时,正常会这样操作:

    CLS1 obj1 = new CLS1(){i = 1, str = "ss"};
    CLS2 obj2 = new CLS2();
    //将 obj1 映射为 obj2
    obj2.i = obj1.i; //obj2.i = 1; 
    obj2.str = obj1.str; //obj2.str = "ss";
    

    如果属性多了,写起来会很繁琐,希望可以通过一个方法自动帮我们解决,比如这样:

    //将 CLS1 的对象映射为 CLS2 的对象
    obj2 = Mapper.T1MapToT2<CLS1, CLS2>(obj1); //obj2.i = 1; obj2.str = "ss";
    

    实现

    以下是实现代码:

    public class Mapper
    {
        /// <summary>
        /// 通过反射,将 T1 映射为 T2
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="t1"></param>
        /// <returns></returns>
        public static T2 T1MapToT2<T1, T2>(T1 t1)
            where T1 : class
            where T2 : class //, new()
        {
            T2 t2 = Activator.CreateInstance<T2>();  //T2 t2 = new T2(); //后面这种写法,要在 where 中添加 new()
            if (t1 == null)
            {
                return t2;
            }
    
            var p1 = t1.GetType().GetProperties();
            var p2 = typeof(T2).GetProperties();
            for (int i = 0; i < p1.Length; i++)
            {
                //条件:1、属性名相同;2、t2属性可写;3、属性可读性一致;4、数据类型相近(相同,或者接近。接近如:int 和 int?)
                var p = p2.Where(t => t.Name == p1[i].Name && t.CanWrite && t.CanRead == p1[i].CanRead).FirstOrDefault();
                if (p == null)
                    continue;
                var v = p1[i].GetValue(t1);
                if (v == null)
                    continue;
                try { p.SetValue(t2, v); } //难判定数据类型,暂时这样处理
                catch
                {
                    try { p.SetValue(t2, Convert.ChangeType(v, p.PropertyType)); } //int? -> object -> int? 会抛错
                    catch { }
                }
    
            }
    
            return t2;
        }
    
        //这种写法和上面的写法没啥差别
        public static T2 T1MapToT2_2<T1, T2>(T1 t1)
            where T1 : class
            where T2 : class //, new()
        {
            T2 t2 = Activator.CreateInstance<T2>();  //T2 t2 = new T2(); //后面这种写法,要在 where 中添加 new()
    
            var p1 = t1.GetType().GetProperties();
            var p2 = typeof(T2);
            for (int i = 0; i < p1.Length; i++)
            {
                //条件:1、属性名相同;2、t2属性可写;3、属性可读性一致;4、数据类型相近(相同,或者接近。接近如:int 和 int?)
                var p = p2.GetProperty(p1[i].Name);
                if (p == null || !p.CanWrite || p.CanRead != p1[i].CanRead)
                    continue;
                var v = p1[i].GetValue(t1);
                if (v == null)
                    continue;
                try { p.SetValue(t2, Convert.ChangeType(v, p.PropertyType)); }
                catch { }
            }
    
            return t2;
        }
    }
    
  • 相关阅读:
    Sql Server数据库使用触发器和sqlbulkcopy大批量数据插入更新
    树莓派安装系统
    ubuntu设置ulimit
    aws申请ec2实例后如何用root用户登录
    python-redis
    Windows Server多用户同时远程登录
    ansible-常用模块
    ansible安装-本机测试
    cmdb实现三种方式
    linux-crond_计划任务
  • 原文地址:https://www.cnblogs.com/clis/p/15192877.html
Copyright © 2011-2022 走看看