簡體   English   中英

根據運行時已知的屬性列表動態創建對象

[英]Dynamically create an object from list of properties known at run-time

我的結果(xml格式, <Prop0><Prop1> ,...)來自要保存到數據庫表中的API。 我將道具映射到表列。 我想動態創建一個對象,其屬性名稱來自映射,值來自API結果。

我可以使用映射字典和API結果直接將值保存在數據庫中,但是所有插入功能(遠程到我的應用程序)都設計為使用對象列表。

我已經探索了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類中已經存在的所有屬性嗎?

除了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;

        }

在C#中動態創建類型的唯一方法是使用System.Reflection.Emit命名空間。 在這種情況下,您不能使用泛型,因為即使未指定類型T ,它仍然暗含類型安全性,這要求在編譯時創建類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM