Skip to content

C# 利用反射复制同名属性

🏷️ C#

下面示例代码仅支持基本类型,T[]List<T> 类型的同名属性转换。

csharp
/// <summary>
/// 复制同名属性
/// </summary>
/// <typeparam name="D">目标类型</typeparam>
/// <typeparam name="S">源类型</typeparam>
/// <param name="s">源数据</param>
/// <returns></returns>
public static D Mapper<D, S>(S s)
{
  D d = Activator.CreateInstance<D>();

  try
  {
    Mapper(s, typeof(S), d, typeof(D));
  }
  catch (Exception ex)
  {
    throw ex;
  }

  return d;
}

/// <summary>
/// 复制同名属性
/// </summary>
/// <param name="s">源数据</param>
/// <param name="typeS">源类型</param>
/// <param name="d">目标数据</param>
/// <param name="typeD">目标类型</param>
private static void Mapper(object s, Type typeS, object d, Type typeD)
{
  if (s == null)
  {
    d = null;
    return;
  }

  foreach (PropertyInfo sp in typeS.GetProperties())//获得类型的属性字段  
  {
    foreach (PropertyInfo dp in typeD.GetProperties())
    {
      // 判断属性名是否相同
      if (dp.Name == sp.Name)
      {
        if (dp.PropertyType == sp.PropertyType)
        {
          dp.SetValue(d, sp.GetValue(s), null);//获得 s 对象属性的值复制给 d 对象的属性  
        }
        else if (dp.PropertyType.FullName.IndexOf("System.Collections.Generic.List") == 0
            && sp.PropertyType.FullName.IndexOf("System.Collections.Generic.List") == 0)
        {
          // 属性名相同的列表且类型不一致时,同样的复制相同属性的值到目标类型实例
          if (sp.GetValue(s) == null)
          {
            dp.SetValue(d, null, null);
          }
          else
          {
            int count = Convert.ToInt32(sp.PropertyType.GetProperty("Count").GetValue(sp.GetValue(s)));
            Type itemTypeS = sp.PropertyType.GenericTypeArguments[0];
            Type itemTypeD = dp.PropertyType.GenericTypeArguments[0];

            object lstD = Activator.CreateInstance(dp.PropertyType); ;
            for (int i = 0; i < count; i++)
            {
              object itemD = Activator.CreateInstance(itemTypeD);
              Mapper(sp.PropertyType.GetProperty("Item").GetValue(sp.GetValue(s), new object[] { i }), itemTypeS, itemD, itemTypeD);

              dp.PropertyType.GetMethod("Add").Invoke(lstD, new object[] { itemD });
            }

            dp.SetValue(d, lstD, null);
          }
        }
        else if (dp.PropertyType.BaseType == typeof(Array) && sp.PropertyType.BaseType == typeof(Array))
        {
          if (sp.GetValue(s) == null)
          {
            dp.SetValue(d, null, null);
          }
          else
          {
            int length = Convert.ToInt32(sp.PropertyType.GetProperty("Length").GetValue(sp.GetValue(s)));
            Type itemTypeS = sp.PropertyType.GetElementType();
            Type itemTypeD = dp.PropertyType.GetElementType();

            object arrD = Array.CreateInstance(itemTypeD, length);
            for (int i = 0; i < length; i++)
            {
              object itemD = Activator.CreateInstance(itemTypeD);
              Mapper(sp.PropertyType.GetMethod("GetValue", new Type[] { typeof(int) }).Invoke(sp.GetValue(s), new object[] { i }), itemTypeS, itemD, itemTypeD);
              dp.PropertyType.GetMethod("SetValue", new Type[2] { itemTypeD, typeof(int) }).Invoke(arrD, new object[] { itemD, i });
            }

            dp.SetValue(d, arrD, null);
          }
        }
        else if (!dp.PropertyType.IsPrimitive && !sp.PropertyType.IsPrimitive)
        {
          object objD = Activator.CreateInstance(dp.PropertyType);
          Mapper(sp.GetValue(s), sp.PropertyType, objD, dp.PropertyType);
          dp.SetValue(d, objD, null);
        }
      }
    }
  }
}