2013-02-20 6 views
0

Кодпреобразование класса с помощью атрибутов

public class Test1 
{ 
    [Conversion("UserId")] 
    Public int id { get; set; } 

    [Conversion("UserValue")] 
    public int value { get; set; } 

    [Conversion("UserInfo")] 
    public List<Test2> info { get; set; } 
} 
public class User 
{ 
    public int UserId { get; set; } 
    public int UserValue { get; set; }  
    public List<UserInformation> UserInfo { get; set; } 
} 

public class Test2 
{ 
    [Conversion("UserId")] 
    public int id { get; set; } 

    [Conversion("UserName")] 
    public string name { get; set; } 

    [Conversion("UserLocation")] 
    public string location { get; set; } 
} 

public class UserInformation 
{ 
    public int UserId { get; set; } 
    public string UserName { get; set; } 
    public string UserLocation { get; set; } 
} 

public class ConversionAttribute  
{ 
    public string Name { get; set; } 
    public ConversionAttribute(string name) 
    { 
     this.Name = name; 
    } 
} 

public dynamic Convert(dynamic source, Type result) 
{ 
    var p = Activator.CreateInstance(result); 
    foreach (var item in source.GetType().GetProperties().Where(m => m.GetCustomAttributes(typeof(ConversionAttribute)).Count() > 0)) 
    { 
     p.GetType().GetProperty(item.GetCustomAttributes(typeof(ConversionAttribute)).Cast<ConversionAttribute>().Name).Value = item.GetValue(source,null); // This should work for system types... but not for lists/custom models.   
    }  
} 

public void DoShit() 
{ 
    var t1 = new Test1 { id = 1, name = value = "Test", info = new Test2 { id = 1, name = "MyName", location = "UserLocation" } }; 
    var obj = Convert(t1, typeof(User)); 
} 

Ситуация

Я была поставлена ​​задача превратить нашу модель базы данных для нашей модели WCF. Они отличаются несколькими способами, которые я показал немного в приведенном выше примере кода.

Мне удалось создать экземпляры с использованием Activator.CreateInstance(result), и я могу использовать source.GetType().GetProperties(), чтобы скопировать все свойства, но у меня, похоже, проблема, связанная с моделью (пользовательским классом) или списком.

Проблема

Я понятия не имею, как обрабатывать пользовательские классы или списки (оба типа системы Aswell как пользовательские классы).

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

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

+0

Есть ли причина, по которой вы не можете переделать свой db, чем использовать ORM, например Entity Framework, для повторного импорта классов модели? – Didaxis

+0

Наша база данных полностью динамична, для одной модели поле может означать «Имя», но для другого это может означать «описание» –

+0

Если вы не хотите обрабатывать событие evry отдельно, вы можете обернуть свой тип источника с помощью специального DynamicObject, который будет маршрутизировать свойство acess вызывает ваш тип источника. – user629926

ответ

0
 Here is something that I tried. It works albeit it's a little slow on lager object graphs. One could use expression trees   which are harder to get but give a really impressive performance. 



     'private static IEnumerable<Tuple<PropertyInfo, PropertyInfo>> MapProperties(Type source, Type target) 
     { 
      var targetProperies = target.GetProperties(); 

      foreach (var property in source.GetProperties()) 
      { 
       var conversionAttribute = 
        property.GetCustomAttributes(typeof (ConvertAttribute), false).FirstOrDefault() as 
        ConvertAttribute; 

       if (conversionAttribute == null) 
        throw new InvalidOperationException(
         String.Format("Source property {0} doesn't have ConvertAttribute defined", property.Name)); 

       var targetProperty = targetProperies.FirstOrDefault(p => p.Name == conversionAttribute.Name); 


       if (targetProperty == null) 
        throw new InvalidOperationException(String.Format(
         "Target type doesn't have {0} public property", conversionAttribute.Name)); 

       yield return Tuple.Create(targetProperty, property); 
      } 
     } 

     public static bool IsIList(Type type) 
     { 
      return type.GetInterface("System.Collections.Generic.IList`1") != null; 
     } 


     private static object Convert(object source, Type resaultType) 
     { 
      var resault = Activator.CreateInstance(resaultType); 

      var sourceType = source.GetType(); 


      if (IsIList(resaultType) && IsIList(sourceType)) 
      { 
       var sourceCollection = source as IList; 

       var targetCollection = resault as IList; 

       var argument = resaultType.GetGenericArguments()[0]; 

       if (argument.IsAssignableFrom(sourceType.GetGenericArguments()[0])) 
       { 
        foreach (var item in sourceCollection) 
        { 
         targetCollection.Add(item); 
        } 
       } 
       else 
       { 
        foreach (var item in sourceCollection) 
        { 
         targetCollection.Add(Convert(item, argument)); 
        } 
       } 
      } 
      else 
      { 
       foreach (var map in MapProperties(sourceType, resaultType)) 
       { 
        if (map.Item1.PropertyType.IsAssignableFrom(map.Item2.PropertyType)) 
        { 
         map.Item1.SetValue(resault, map.Item2.GetValue(source, null), null); 
        } 
        else 
        { 
         map.Item1.SetValue(resault, 
              Convert(map.Item2.GetValue(source, null), map.Item1.PropertyType), null); 
        } 
       } 
      } 
      return resault; 
     }'