前言

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

比如我们有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;
}
}

C# 通过反射实现对象映射:将2个属性相近的对象相互转换的更多相关文章

  1. Powermockito 针对方法中new 对象的模拟,以及属性中new 对象的模拟

    PowerMocker 是一个功能逆天的mock 工具. 一,Powermockito 针对方法中new 对象的模拟 // 如何才能mock掉 WeChatConfigUtil 这个类,让 weCha ...

  2. Python与数据库[2] -> 关系对象映射/ORM[2] -> 建立声明层表对象的两种方式

    建立声明层表对象的两种方式 在对表对象进行建立的时候,通常有两种方式可以完成,以下是两种方式的建立过程对比 首先导入需要的模块,获取一个声明层 from sqlalchemy.sql.schema i ...

  3. PHP设计模式笔记六:数据对象映射模式 -- Rango韩老师 http://www.imooc.com/learn/236

    数据对象映射模式 1.数据对象映射模式,是将对象和数据存储映射起来,对一个对象的操作会映射为对数据存储的操作 2.在代码中实现数据对象映射模式,我们将实现一个ORM类,将复杂的SQL语句映射成对象属性 ...

  4. 处理Selection对象和Range对象——Word VBA中重要的两个对象

    处理Selection对象和Range对象——Word VBA中重要的两个对象 Word 开发人员参考Selection 对象代表窗口或窗格中的当前所选内容.所选内容代表文档中选定(或突出显示)的区域 ...

  5. Android 学习笔记之AndBase框架学习(五) 数据库ORM..注解,数据库对象映射...

    PS:好久没写博客了... 学习内容: 1.DAO介绍,通用DAO的简单调度过程.. 2.数据库映射关系... 3.使用泛型+反射+注解封装通用DAO.. 4.使用AndBase框架实现对DAO的调用 ...

  6. 关于对象映射(Dto->model) 思路的一些想法

    最近粗浅的学习了下AutoMapper 这个做对象映射的第三方工具,觉得非常方便使用,所以简单的总结了一下我能想到的简单的对象映射的方式. 占时先不考虑源对象成员到目标对象成员的指定映射(即成员名不一 ...

  7. C# 高性能对象映射(表达式树实现)

    前言 上篇简单实现了对象映射,针对数组,集合,嵌套类并没有给出实现,这一篇继续完善细节. 开源对象映射类库映射分析 1.AutoMapper 实现原理:主要通过表达式树Api 实现对象映射 优点: . ...

  8. ASP.NET CORE 中使用AutoMapper进行对象映射

    ASP.NET CORE 中使用AutoMapper进行对象映射 1.什么是AutoMapper? AutoMapper是基于对象到对象约定的映射工具,常用于(但并不仅限制于)把复杂的对象模型转为DT ...

  9. Mybaits的中的对象映射(包含仅有基本数据类型的属性的和对象类型的属性的)

    转:https://blog.csdn.net/cjt20100/article/details/46547617. 1 constructor – 用来将结果反射给一个实例化好的类的构造器    a ...

随机推荐

  1. C语言:float类型%d输出

    float类型%d输出 float a=7.5f; 如果用printf("%d",a);输出的是0. 但float型用%d输出是否一定是0呢,答案肯定不都是0: 为什么 7.5 用 ...

  2. ES6新增语法(四)——面向对象

    ES6中json的2个变化 简写:名字和值相同时,json可以可以简写 let a=12,b=5; let json = { a, b } console.log(json) // { a:12 , ...

  3. 【LeetCode】724. 寻找数组的中心下标

    724. 寻找数组的中心下标 知识点:数组:前缀和: 题目描述 给你一个整数数组 nums ,请计算数组的 中心下标 . 数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的 ...

  4. Redis学习——数据结构上

    一.常用的全局命令 1.查看所有的键: KEYS * KEYS pattern:查找所有符合给定模式 pattern 的 key . KEYS 的速度非常快,但在一个大的数据库中使用它仍然可能造成性能 ...

  5. Appium - monkey自定义脚本实践(四)

    monkey自定义脚本实践 一.获取元素坐标点位置 二.Monkey脚本API简介 常规Monkey测试执行的是随机的事件流,但如果只是想让Monkey测试某个特定场景这时候就需要用到自定义脚本了,M ...

  6. js实现0ms延时定时器的几种方式

    这两天看到一篇介绍<如何实现准时的 setTimeout?>的文章,文章起源于一道面试题:有什么办法让setTimeout准时呀?具体文章内容可查看附录[1],看完之后,引起了我对setT ...

  7. OpenSUSE Leap 42.1 KDE Ultmate Linux Distribution终极Linux系统试用与SSH连接

    系统安装环境: #一台旧笔记本电脑 #CPU Intel(R) Core(TM) i3 M 380 2.53GHz (4核) #内存 1G #硬盘存储 250G #系统型号 OpenSUSE Leap ...

  8. 带标签的for循环

    for循环可以加标签,使用break或者continue时,若存在多层嵌套循环可指定标签的for循环 public class ForLabel { public static void main(S ...

  9. 【水】Dev-c++黑暗模式教程

    前言 大家有没有觉得盯着Dev-c++那个白花花的背景盯久了之后会觉得眼睛不舒服-- 本人今天就来给大家带来一个黑暗模式的Dev-c++,可以让眼睛没那么难受(本人亲测有效) 效果如下图(猛男警告): ...

  10. netty系列之:中国加油

    目录 简介 场景规划 启动Server 启动客户端 消息处理 消息处理中的陷阱 总结 简介 之前的系列文章中我们学到了netty的基本结构和工作原理,各位小伙伴一定按捺不住心中的喜悦,想要开始手写代码 ...