【问题标题】:Dynamically create an object from list of properties known at run-time从运行时已知的属性列表动态创建对象
【发布时间】:2017-09-02 21:52:03
【问题描述】:

我的结果(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 中的情况下完成相同的操作吗?

【问题讨论】:

  • “我已经探索过 System.Dynamic.ExpandoObject,但不能即时向它添加属性(例如,来自字典)。” - 是的,你可以 - 它实现了 IDictionary&lt;string,object&gt; - 只是强制转换到此为止,您可以执行obj["Foo"] = 123; 等 - 请参见此处的示例:stackoverflow.com/a/43276768/23354
  • @MarcGravell。哦,是的!即使我读到它实现了 IDictionary,我也没有想到它。它符合我的目的,非常感谢!如果您将其发布为答案,我可以将其标记为答案。

标签: c# dynamic type-conversion


【解决方案1】:

在 C# 中动态创建类型的唯一方法是使用 System.Reflection.Emit 命名空间。在这种情况下不能使用泛型,因为即使没有指定类型 T,它仍然意味着类型安全,这需要在编译时创建类型。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2017-09-02
      • 1970-01-01
      • 1970-01-01
      • 2016-12-17
      • 2015-08-07
      • 2018-04-16
      • 2014-10-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多