前言: 兩年前寫過一個 反射實現不同模型相同屬性賦值 只能簡單的實現兩個model 相同屬性名,相同類型賦值
最近又遇到這個問題,需要對相同屬性名或者指定屬性名 不同類型(復雜對象,如:List<class1> 到list<class2>)對象賦值,所有之前的代碼就不能用了
花了點時間把這個代碼給完善了點點
需求:1.對不同model中的相同屬性名賦值 如:Class1中Name 賦值到 Class2中Name
2.對不同model中的不同屬性名賦值 如:Class1中Name 賦值到 Class2中Uname
3.對不同model中的相同屬性名(集合對象)賦值,集合對象賦值要分4種情況
3.1.兩個model中集合對象都是List集合 如:Class1中List<User1> 賦值到 Class2中List<User2>
3.2.兩個model中集合對象都是數組(Array) 如:Class1中User1[] 賦值到 Class2中User2[]
3.3.一個model中是List,一個里面是Array 如:Class1中List<User1> 賦值到 Class2中User2[]
3.4.一個model中是Array,一個是List 如:Class1中User1[] 賦值到 List<User2>
大概需求就是如上,不考慮基礎數據類型轉換,如:Class1中Time(數據類型String) 到 Class2中Time(數據類型Datetime)
這里不再對需求1進行討論,可以直接使用兩年前寫的
話不多說,先貼代碼,再解釋.
1.常量
private static readonly string ListTypeName = typeof (List<>).Name; //用於判定是否是List集合
2.主函數
/// <summary> /// 模型賦值 /// </summary> /// <param name="source">數據源模型</param> /// <param name="target">目標模型</param> /// <param name="pars">數據源模型指定屬性值 賦值 到目標模型指定屬性,例:Key=Name,Value=Uname 把數據模型Name屬性賦給目標模型Uname</param> public static void CopyModel(object source, object target, Dictionary<string, string> pars) { //獲取Type Type ttarget = target.GetType(); Type tsource = source.GetType(); //根據 數據模型 來對 目標模型 賦值 //循環數據模型所有公共屬性 foreach (var sourceAttr in tsource.GetProperties()) { //pars.ContainsKey(sourceAttr.Name) 得到不同屬性名,用來實現 數據模型Name屬性賦給目標模型Uname PropertyInfo targetAttr = ttarget.GetProperty(pars.ContainsKey(sourceAttr.Name) ? pars[sourceAttr.Name] : sourceAttr.Name);//獲取目標模型屬性Name==數據模型屬性Name(得到目標屬性) if (targetAttr == null) //為null標識目標模型中沒有該屬性,進入下次循環 continue; try { //獲取兩個model屬性類型 var targetProType = targetAttr.PropertyType; var sourceProType = sourceAttr.PropertyType; //list->list 判斷兩個屬性類型是否為list if (targetProType.Name == ListTypeName && sourceProType.Name == ListTypeName) { var miValue = (IList)sourceAttr.GetValue(source, null); //得到數據模型中該屬性的數據,直接轉為IList CopeToList(miValue, target, pars, targetAttr); //調用賦值 return; } //array->array 判斷兩個屬性類型是否為array if (targetProType.IsArray && sourceProType.IsArray) { var miValue = (Array)sourceAttr.GetValue(source, null); //得到數據模型中該屬性的數據,直接轉為Array CopyToArray(miValue, miValue.Length, target, pars, targetAttr); //調用賦值 return; } //list->array 當數據屬性類型為List 目標屬性類型為Array if (targetProType.IsArray && sourceProType.Name == ListTypeName) { var miValue = (IList)sourceAttr.GetValue(source, null); //得到數據模型中該屬性的數據,直接轉為IList CopyToArray(miValue, miValue.Count, target, pars, targetAttr); //調用賦值 return; } //array->list 當數據屬性類型為Array 目標屬性類型為List if (targetProType.Name == ListTypeName && sourceProType.IsArray) { var miValue = (Array)sourceAttr.GetValue(source, null); //得到數據模型中該屬性的數據,直接轉為Array CopeToList(miValue, target, pars, targetAttr); //調用賦值 return; } //基礎數據類型賦值 var s = sourceAttr.GetValue(source, null); targetAttr.SetValue(target, s, null); } catch { } } }
3.CopeToList
/// <summary> /// 集合數據賦值 賦值到List /// </summary> /// <param name="data">數據集合</param> /// <param name="target">目標模型</param> /// <param name="pars">數據源模型指定屬性值 賦值 到目標模型指定屬性</param> /// <param name="targetAttr">目標屬性</param> private static void CopeToList(IEnumerable data, object target, Dictionary<string, string> pars, PropertyInfo targetAttr) { if (data == null) return; //獲取目標屬性類型 var targetProType = targetAttr.PropertyType; //得到目標屬性值 var desValue = (IList)targetAttr.GetValue(target, null); if (desValue == null) //如果List為null 需要new List<T>(); { var newlist = Activator.CreateInstance(targetProType); //根據目標屬性類型實例化List,如:目標屬性為List<Class1> targetAttr.SetValue(target, newlist, null); //把newlist寫入(賦值)目標屬性 desValue = (IList)targetAttr.GetValue(target, null); //再次獲取目標屬性值 } var desMethod = targetProType.GetMethod("Add"); //獲取到List.Add方法 var modelType = targetProType.GetGenericArguments()[0]; //獲取List<T>中 T的類型 foreach (var v in data) //循環數據集合 { var model = Activator.CreateInstance(modelType); //創建T實例 CopyModel(v, model, pars); //調用模式賦值 desMethod.Invoke(desValue, new[] { model }); //調用List.Add方法,將數據對象Add到目標屬性(List)中 } }
4.CopyToArray
/// <summary> /// 集合數據賦值 賦值到數組(Array) /// </summary> /// <param name="data">數據集合</param> /// <param name="count">數據條數(由於IEnumerable不方便獲取數據條數,所有這里通過外面傳入參數)</param> /// <param name="target">目標模型</param> /// <param name="pars">數據源模型指定屬性值 賦值 到目標模型指定屬性</param> /// <param name="targetAttr">目標屬性</param> private static void CopyToArray(IEnumerable data,int count, object target, Dictionary<string, string> pars, PropertyInfo targetAttr) { if (data == null) return; //獲取目標屬性類型 var targetProType = targetAttr.PropertyType; var arr = Type.GetType(targetProType.FullName); //根據目標數組對象實例化心的數組對象 var newarr = (Array)arr.InvokeMember("Set", BindingFlags.CreateInstance, null, arr, new object[] { count }); //調用數組Set方法設置數組長度,長度為count var modelType = Type.GetType(targetProType.FullName.Replace("[]", "")); //獲取數組元素類型 int c = 0; //用來為數組數據位置定位 foreach (var v in data) { var model = Activator.CreateInstance(modelType); //實例化數組元素對象 CopyModel(v, model, pars); //調用賦值 newarr.SetValue(model, c); //用SetValue方法進行賦值 c++; } targetAttr.SetValue(target, newarr, null); //將新數組直接賦值到目標屬性 }
解釋
上面代碼注釋應該還算比較詳細吧,下面就來列舉上面代碼的使用
需求1.這個就不舉例子了,應該很好理解
需求2.
model:

public class User1 { public string Name{ get; set; } } public class User2 { public string Uname { get; set; } }
用法:
User1 u1 = new User1 {Name="tom"} User2 u2 = new User2 (); Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add("Name","Uname") CopyModel(u1,u2, dic);
需求3.1.
model:

public class User1 { public List<Test> Test { get; set; } } public class User2 { public List<Test2> Test { get; set; } } public class Test { public string Name { get; set; } } public class Test2 { public string Name { get; set; } }
用法:
User1 u1 = new User1 (); u1.Test = new List<Test>(); u1.Test.Add(new Test { Name = "11"}); u1.Test.Add(new Test { Name = "22" }); u1.Test.Add(new Test {Name = "33"}); User2 u2 = new User2(); Dictionary<string, string> dic = new Dictionary<string, string>(); CopyModel(u1,u2, dic);
需求3.2
model:

public class User1 { public Test[] Test { get; set; } } public class User2 { public Test2[] Test { get; set; } }
用法:同上
需求3.3:
model:

public class User1 { public List<Test> Test { get; set; } } public class User2 { public Test2[] Test { get; set; } }
用法:同上
需求3.4:

public class User1 { public Test2[] Test { get; set; } } public class User2 { public List<Test> Test { get; set; } }
同法:同上
總結:大致需求就是解決上述模型賦值問題,此方法由於賦值調用自身,可以實現無限下級模型賦值 如:User1.Test為復雜對象集合,Test類中也有復雜集合對象,無限讓下執行
對與復雜集合內不同屬性賦值也通過Dictionary傳入, 如:User1.Test中Test.Name 賦值到Test2.Uname
我不曉得我表述清楚沒有,反正大家慢慢看吧(我的錯別字也是不太多,別介意→_→ )