使用c#中的反射设置复杂属性值

时间:2014-03-05 21:24:38

标签: c#

我已经阅读了几个类似于我的问题的问题,但是我对这些概念的理解缺乏一般答案不足以回答我的具体问题的地方,即:

我有一个域对象,我从db调用实例化:

public class dbRecord {
    public decimal RecordCode {get;set;}
    public string  FirstName {get; set;}
    ... 40 more fields ....
}

我有另一个存储过程调用,它提取我需要与第一个对象合并并创建的列元数据(未显示):

public class ViewRecord {
    public MetadataRecord<decimal> RecordCode {get;set;}
    public MetadataRecord<string> FirstName {get; set;}
    ... 40 more fields ....
}

MetadataRecord对象是:

public class MetadataRecord<T>{
    public T ColumnValue {get;set;}
    public bool IsFrozen {get;set;}
    public string ValidatorFieldName {get;set;}
}

我可以通过手动映射创建ViewRecord对象:

var newFile = new ViewRecord();
newFile.RecordCode.ColumnValue = dbRecord.RecordCode;
... 40 more times ...

但我认为我可以用反射来构建它:

var startFile = ...dbRecord from db result...
var newFile = new ViewRecord();
foreach (var startProp in startFile.GetType().GetProperties()) {
    foreach (var newProp in newFile.GetType().GetProperties()) {
        if (startProp.Name == newProp.Name) {
              PropertyInfo valProp = typeof(MetadataRecord<>).GetProperty("ColumnValue");
                    var data = startProp.GetValue(startFile, null);
                    valProp.SetValue(valProp, data, null);
        }
     }
}

这一直到我尝试设置值的位置,我得到以下异常:

  

无法对ContainsGenericParameters为true的类型或方法执行后期绑定操作。

任何人都可以帮我找出一种不同/更好的方法来完成这项工作吗?整个问题是我们必须在运行时添加到db记录的字段级元数据,这导致我失去了这个兔子洞!

任何帮助都将不胜感激。

UPDATE 好的,我现在看到,newPropType必须实例化并分配:

var instanceType = Activator.CreateInstance(newPropType);
...
valProp.SetValue(instanceType, data);
newProp.SetValue(newFile, instanceType);

谢谢你的回答,安德鲁!

道具也向kkilton@gmail.com提供了关于Activator.CreateInstance的提示。

1 个答案:

答案 0 :(得分:-1)

您需要完全指定元数据属性的泛型类型。

PropertyInfo valProp = typeof(MetadataRecord<>).MakeGenericType(startProp.PropertyType).GetProperty("ColumnValue");

或更可读:

Type newPropType = typeof(MetadataRecord<>).MakeGenericType(startProp.PropertyType);
PropertyInfo valProp = newPropType.GetProperty("ColumnValue");

您需要在值设置行中使用元数据对象:

var metadataObj = newProp.GetValue(newFile);
valProp.SetValue(metadataObj, data, null);