2013-02-20 56 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()來複制所有屬性,但是對於Model(自定義類)或列表,我似乎遇到了問題。

問題

我不知道如何處理自定義類或列表(兩個系統類型藏漢定製類)。

在我以前的方法中,我使用了兩種方法,一種用於正常轉換,另一種用於列表轉換..但是我的老闆不批准它,所以我想知道是否可以使用一種方法每次使用時不檢查類型是否是列表,自定義類或系統類型

這是必須完全通用並且通過使用屬性的主要原因是因爲我們計劃在多個項目中使用此方法以及超過100個型號。

+0

是否有一個原因,你不能重新設計你的數據庫,比使用ORM像實體框架重新導入你的模型類? – Didaxis 2013-02-20 18:25:45

+0

我們的數據庫是完全動態的,對於一個模型字段可能意味着「名稱」,但另一個模型可能意味着「描述」 – 2013-02-21 12:49:02

+0

如果你不想處理evry的情況分離你可以包裝你的源類型通過自定義動態對象將路由財產援助調用您的源類型。 – user629926 2013-02-21 17:50:13

回答

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; 
     }'