2017-04-07 85 views
0

我有一個來自我保存到我的數據庫表中的API的結果(xml格式,<Prop0><Prop1>,...)。我有一個映射到我的表列的道具。我想通過來自API結果的映射和值的屬性名稱即時創建一個對象。從運行時已知屬性列表動態創建一個對象

我可以使用映射字典和API結果直接保存數據庫中的值,但是所有插入函數(對於我的應用程序來說都是遠程的)都被設計爲使用List對象。

我已經探索過System.Dynamic.ExpandoObject,但是不能隨意添加屬性(例如字典)。目前,我正在使用以下泛型但強類型的解決方案,爲此需要在該類中提供所有屬性。

internal T FetchPopulatedObject<T>(Dictionary<string, string> apiToTableMapping, Dictionary<string, string> apiResultsKeyVal, T objectToPopulate) where T : new() 
{ 
    if (objectToPopulate == null) 
    objectToPopulate = new T(); 

    PropertyInfo currProp; 
    Type currActualType; 
    string valToSet = string.Empty; 
    int valToSetNumeric = 0; 
    object finalValToSet = new object(); 

    foreach (KeyValuePair<string, string> currMap in apiToTableMapping) 
    { 
    valToSet = string.Empty; 
    currProp = (typeof(T).GetProperty(currMap.Value)); 
    if (currProp == null) 
    { 
     log.Info("Could not find property for table column " + currMap.Value + ". Moving on."); 
     continue; 
    } 
    bool valResult = apiResultsKeyVal.TryGetValue(currMap.Key, out valToSet); 
    if (!valResult) 
    { 
     log.Info("Could not find value in API Results for property: " + currMap.Key + "."); 
     continue; 
    } 

    currActualType = Nullable.GetUnderlyingType(currProp.PropertyType) ?? currProp.PropertyType; 

    if (string.IsNullOrEmpty(valToSet)) 
    { 
     log.Info("Property " + currProp.Name + " is of " + currProp.PropertyType.Name + " type but API attribute " + 
     currMap.Key + " returned an incompatible or empty value " + valToSet + ". Skipping this field."); 
     continue; 
    } 
    else 
    { 
     finalValToSet = Int32.TryParse(valToSet, out valToSetNumeric) ? Convert.ChangeType(valToSetNumeric, currActualType) : Convert.ChangeType(valToSet, currActualType); 
    } 

    currProp.SetValue(objectToPopulate, finalValToSet, null); 
    } 

    return objectToPopulate; 

} 

但是,這是不可行的,因爲API結果不斷變化並添加新屬性。

有人可以建議如何做到這一點,而不必擁有T類中的所有屬性嗎?

+1

「我已經探索System.Dynamic.ExpandoObject但在運行它,一不能加屬性(,比如說,從一個字典)「 - 是的,你可以 - 它實現了'IDictionary ' - 只需將其轉換爲''obj ['Foo'] = 123;'etc - 請參閱示例:http:/ /stackoverflow.com/a/43276768/23354 –

+0

@MarcGravell。哦,是啊!即使我閱讀它實現了IDictionary,它之前沒有發生過。它服務於我的目的,非常感謝!如果您將它作爲一個發佈,我可以將其標記爲答案。 – Quester

回答

0

在C#中動態創建類型的唯一方法是使用System.Reflection.Emit命名空間。在這種情況下,不能使用泛型,因爲即使沒有指定類型T,它仍然意味着類型安全,這需要在編譯期間創建類型。

1

以外的Emit,我只能想到一個動態編譯的類型,例如:

 static Type GetMeAType(string myTypeName, string myStringPropertyName) { 

      string codeToCompile = "using System; public class " + myTypeName + " {public string " + 
            myStringPropertyName + " { get; set; } }"; 
      string[] references = { "System.dll", "System.Core.dll" }; 

      CompilerParameters compilerParams = new CompilerParameters(); 

      compilerParams.GenerateInMemory = true; 
      compilerParams.TreatWarningsAsErrors = false; 
      compilerParams.GenerateExecutable = false; 
      compilerParams.CompilerOptions = "/optimize"; 
      compilerParams.ReferencedAssemblies.AddRange(references); 

      CSharpCodeProvider provider = new CSharpCodeProvider(); 
      CompilerResults compile = provider.CompileAssemblyFromSource(compilerParams, codeToCompile); 
      Module dynamicModule = compile.CompiledAssembly.GetModules()[ 0 ]; 
      var type = dynamicModule.GetType(myTypeName); 

      return type; 

     }