反射 實現不同模型相同屬性賦值 第二集(automapper)


前言: 兩年前寫過一個 反射實現不同模型相同屬性賦值  只能簡單的實現兩個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; }
}
View Code

用法:

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; }
}
View Code

用法:

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; }
}
View Code

用法:同上

需求3.3:

model:

public  class User1
{
    public List<Test> Test { get; set; }
}

public  class User2
{
    public Test2[] Test { get; set; }
}
View Code

用法:同上

需求3.4:

public  class User1
{
    public Test2[] Test { get; set; }
}

public  class User2
{
    public List<Test> Test { get; set; }
}
View Code

同法:同上


 

總結:大致需求就是解決上述模型賦值問題,此方法由於賦值調用自身,可以實現無限下級模型賦值 如:User1.Test為復雜對象集合,Test類中也有復雜集合對象,無限讓下執行

   對與復雜集合內不同屬性賦值也通過Dictionary傳入, 如:User1.Test中Test.Name 賦值到Test2.Uname

我不曉得我表述清楚沒有,反正大家慢慢看吧(我的錯別字也是不太多,別介意→_→ ) 

 

原帖地址:http://www.cnblogs.com/jio92/p/CopyModel.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM