2013-05-26 2 views
3

У меня есть следующий метод, который я могу использовать, чтобы преобразовать объект данного типа:«Deep» Преобразование объекта

public static TTarget Convert<TTarget>(object source) where TTarget : new() 
{ 
    var target = new TTarget(); 

    Type targetType = typeof (TTarget); 
    foreach (PropertyInfo sourceProperty in source.GetType().GetProperties()) 
    { 
     if (!sourceProperty.CanRead || (sourceProperty.GetIndexParameters().Length > 0)) 
      continue; 

     PropertyInfo targetProperty = targetType.GetProperty(sourceProperty.Name); 

     if ((targetProperty != null) && (targetProperty.CanWrite)) 
      targetProperty.SetValue(target, sourceProperty.GetValue(source, null), null); 
    } 
    return target; 
} 

Он отлично работает для простых классов со свойствами быть типы значений и так далее, но сложные свойства, которые необходимо сопоставить с другим классом, не совсем понятно, как это сделать. Если хранить отображения в статическое свойство:

private static Dictionary<Type, Type> Mappings; 

static TypeConverter() 
{ 
    Mappings = new Dictionary<Type, Type> 
     { 
      {typeof (DbSpace), typeof (DmsSpace)}, 
      {typeof (DbDirectory), typeof (DmsDirectory)}, 
      {typeof (DbFile), typeof (DmsFile)} 
     }; 
} 

Я, кажется, не найти способ, чтобы найти способ, чтобы использовать эту информацию для преобразования сложных свойств. Как я могу использовать приведенные выше сопоставления для преобразования сложных свойств?

Суть проблемы: как я могу позвонить new, если у меня есть только объект Type?

ответ

4

Activator.CreateInstance(type), вот ссылка на msdn для тех, которые думают, что мой ответ не был «разработать» достаточно (получил 3 downvotes для точечно, как к коротким, как-надо ответить) ...

У вас также посмотрел AutoMapper?

+0

просто использовать автоматический картограф, сделать имена свойств точно так же, где это возможно –

+0

Совершенных оба подхода был успешным. Я опубликовал свои ответы ниже, чтобы другие могли использовать их, если им это нужно. – Candide

2

Вы можете использовать много сериализаторов (JavaScriptSerializer, XmlSerializer, Json.Net и т.д.) сделать «глубокую новообращенный» ваш объект до тех пор, как матч имен Собствености.

дам пример использования JavaScriptSerializer

var class1 = new Class1() { Property = "a", SubProperty = new SubClass1() { SubProperty = "b" } }; 
var class2 = Convert<Class2>(class1); 


public static TTarget Convert<TTarget>(object source) where TTarget : new() 
{ 
    var ser = new JavaScriptSerializer(); 
    var json = ser.Serialize(source); 
    return ser.Deserialize<TTarget>(json); 
} 

.

public class Class1 
{ 
    public string Property { get; set; } 
    public SubClass1 SubProperty { get; set; } 
} 

public class SubClass1 
{ 
    public string SubProperty { get; set; } 
} 


public class Class2 
{ 
    public string Property { get; set; } 
    public SubClass2 SubProperty { get; set; } 
} 

public class SubClass2 
{ 
    public string SubProperty { get; set; } 
} 
0

Решение с использованием Activator.CreateInstance:

public static class TypeConverter 
{ 
    private static Dictionary<Type, Type> Mappings; 

    static TypeConverter() 
    { 
     Mappings = new Dictionary<Type, Type> 
      { 
       {typeof (DbSpace), typeof (DmsSpace)}, 
       {typeof (DbDirectory), typeof (DmsDirectory)}, 
       {typeof (DbFile), typeof (DmsFile)} 
      }; 
    } 

    public static object Convert(object source, Type targetType) 
    { 
     var target = Activator.CreateInstance(targetType); 

     foreach (PropertyInfo sourceProperty in source.GetType().GetProperties()) 
     { 
      if (!sourceProperty.CanRead || (sourceProperty.GetIndexParameters().Length > 0)) 
       continue; 

      PropertyInfo targetProperty = targetType.GetProperty(sourceProperty.Name); 

      object value = sourceProperty.GetValue(source, null); 

      if ((targetProperty != null) && (targetProperty.CanWrite)) 
      { 
       if (value != null) 
       { 
        Type valueType = value.GetType(); 
        Type mappedTypeKey = Mappings.Keys.FirstOrDefault(valueType.IsAssignableFrom); 
        if (mappedTypeKey != null) 
        { 
         targetProperty.SetValue(target, Convert(value, Mappings[mappedTypeKey]), null); 
        } 
        else 
        { 
         targetProperty.SetValue(target, value, null); 
        } 
       } 
       else 
       { 
        targetProperty.SetValue(target, null, null); 
       } 
      } 

     } 
     return target; 
    } 

    public static TTarget Convert<TTarget>(object source) where TTarget : class, new() 
    { 
     return Convert(source, typeof (TTarget)) as TTarget; 
    } 
} 

Пример кода с помощью моего TypeConverter класс:

spaces = ctx.DbSpaces.Include("Root").ToList().Select(TypeConverter.Convert<DmsSpace>).ToList(); 

Решение с использованием AutoMapper:

Mapper.CreateMap<DbSpace, DmsSpace>(); 
Mapper.CreateMap<DbSpace, IDmsSpace>(); 
Mapper.CreateMap<DbDirectory, DmsDirectory>(); 
Mapper.CreateMap<DbDirectory, IDmsDirectory>(); 

Пример кода USI нг AutoMapper:

spaces = ctx.DbSpaces.Include("Root").ToList().Select(Mapper.Map<DmsSpace>).ToList();