前言

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

比如我們有2個類:

  1. //第1個類 CLS1
  2. class CLS1
  3. {
  4. public int i {get; set;}
  5. public string str {get; set;}
  6. }
  7. //第2個類 CLS2
  8. class CLS2
  9. {
  10. public int i {get; set;}
  11. public string str {get; set;}
  12. }

兩個類都擁有屬性 istr

當我們需要將 CLS1 的例項物件轉化為 CLS2 的例項物件時,正常會這樣操作:

  1. CLS1 obj1 = new CLS1(){i = 1, str = "ss"};
  2. CLS2 obj2 = new CLS2();
  3. //將 obj1 對映為 obj2
  4. obj2.i = obj1.i; //obj2.i = 1;
  5. obj2.str = obj1.str; //obj2.str = "ss";

如果屬性多了,寫起來會很繁瑣,希望可以通過一個方法自動幫我們解決,比如這樣:

  1. //將 CLS1 的物件對映為 CLS2 的物件
  2. obj2 = Mapper.T1MapToT2<CLS1, CLS2>(obj1); //obj2.i = 1; obj2.str = "ss";

實現

以下是實現程式碼:

  1. public class Mapper
  2. {
  3. /// <summary>
  4. /// 通過反射,將 T1 對映為 T2
  5. /// </summary>
  6. /// <typeparam name="T1"></typeparam>
  7. /// <typeparam name="T2"></typeparam>
  8. /// <param name="t1"></param>
  9. /// <returns></returns>
  10. public static T2 T1MapToT2<T1, T2>(T1 t1)
  11. where T1 : class
  12. where T2 : class //, new()
  13. {
  14. T2 t2 = Activator.CreateInstance<T2>(); //T2 t2 = new T2(); //後面這種寫法,要在 where 中新增 new()
  15. if (t1 == null)
  16. {
  17. return t2;
  18. }
  19. var p1 = t1.GetType().GetProperties();
  20. var p2 = typeof(T2).GetProperties();
  21. for (int i = 0; i < p1.Length; i++)
  22. {
  23. //條件:1、屬性名相同;2、t2屬性可寫;3、屬性可讀性一致;4、資料型別相近(相同,或者接近。接近如:int 和 int?)
  24. var p = p2.Where(t => t.Name == p1[i].Name && t.CanWrite && t.CanRead == p1[i].CanRead).FirstOrDefault();
  25. if (p == null)
  26. continue;
  27. var v = p1[i].GetValue(t1);
  28. if (v == null)
  29. continue;
  30. try { p.SetValue(t2, v); } //難判定資料型別,暫時這樣處理
  31. catch
  32. {
  33. try { p.SetValue(t2, Convert.ChangeType(v, p.PropertyType)); } //int? -> object -> int? 會拋錯
  34. catch { }
  35. }
  36. }
  37. return t2;
  38. }
  39. //這種寫法和上面的寫法沒啥差別
  40. public static T2 T1MapToT2_2<T1, T2>(T1 t1)
  41. where T1 : class
  42. where T2 : class //, new()
  43. {
  44. T2 t2 = Activator.CreateInstance<T2>(); //T2 t2 = new T2(); //後面這種寫法,要在 where 中新增 new()
  45. var p1 = t1.GetType().GetProperties();
  46. var p2 = typeof(T2);
  47. for (int i = 0; i < p1.Length; i++)
  48. {
  49. //條件:1、屬性名相同;2、t2屬性可寫;3、屬性可讀性一致;4、資料型別相近(相同,或者接近。接近如:int 和 int?)
  50. var p = p2.GetProperty(p1[i].Name);
  51. if (p == null || !p.CanWrite || p.CanRead != p1[i].CanRead)
  52. continue;
  53. var v = p1[i].GetValue(t1);
  54. if (v == null)
  55. continue;
  56. try { p.SetValue(t2, Convert.ChangeType(v, p.PropertyType)); }
  57. catch { }
  58. }
  59. return t2;
  60. }
  61. }