前言

我們在程式設計過程中,經常需要將一個物件轉成另一個物件(一般稱為物件對映)。

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