使用泛型类型和隐式转换的反射

时间:2009-07-20 17:15:49

标签: c# reflection openxml

我正在尝试使用反射来设置某些OpenXML类型的属性(例如Justification)。通过列举所有可能性来分配值是直截了当的:

// attr is an XmlAttribute, so .Name and .Value are Strings
if (attr.Name == "Val")
{
    if (element is Justification)
    {
        ((Justification)element).Val = (JustificationValues)Enum.Parse(typeof(JustificationValues), attr.Value);
            return;
    }
    else
    {
        // test for dozens of other types, such as TabStop
    }
}

通过反思使这很难做的是: 1)Val属性的类型是EnumValue< T>,所以我不知道如何提取要传递的类型作为Enum.Parse的第一个参数。 2)存在从实际枚举类型到EnumValue<>的隐式转换。类型,我不知道如何用反射调用。

我希望代码最终看起来像:

PropertyInfo pInfo = element.GetType().GetProperty(attr.Name);
Object value = ConvertToPropType(pInfo.PropertyType, attr.Value); /* this 
    would return an instance of EnumValue<JustificationValues> in this case */
pInfo.SetValue(element, value, null);

如何实现ConvertToPropType?或者有更好的解决方案吗?

由于

编辑: 我使用Earwicker的建议得到了一个解决方案,但它依赖于一个方便的事实,即枚举的类型名称可以从节点的类型名称(“Justification” - &gt;“JustificationValues”)派生。不过,我仍然很好奇如何解决这个问题。

EDIT2: GetGenericArguments让我完成剩下的工作。感谢。

3 个答案:

答案 0 :(得分:4)

如果属性值只是一个字符串,我假设您已经有一些方法可以确定字符串是否标识了特定枚举中的值。在您的示例中,您将其硬编码,因此我不确定这是您想要的还是您想要更改的内容。

假设您知道它是枚举,并且您知道哪个枚举,您已经知道如何获取包含右enum类型的盒装值的对象,就像在您的代码段中一样。

现在,如果我假设EnumValue<T>有一个带T的构造函数。

Type genericType = typeof(EnumValue<>);
Type concreteType = genericType.MakeGenericType(typeof(JustificationValues));

现在concreteTypeEnumValue<JustificationValues>类型。

从那里你可以得到一个构造函数,希望有一个JustificationValues参数和Invoke它。

<强>更新

啊,我看到你现在在做什么。您使用XML属性名称来选择C#属性。您需要能够检测该属性是否属于EnumValue<T>类型,并找出T是什么。

PropertyInfo p = // ... get property info

Type t = p.GetType();

if (t.IsGenericType && 
    t.GetGenericTypeDefinition == typeof(EnumValue<>))
{
    Type e = t.GetGenericArguments()[0]; // get first (and only) type arg

    // e is the enum type...

试一试。

答案 1 :(得分:1)

.Net 4.0增加了对后期绑定隐含或显式转换的支持。这在开源框架ImpromptuInterface中得到了简化,其静态方法称为InvokeConvert。在你理想的例子中,它会像这样工作:

PropertyInfo pInfo = element.GetType().GetProperty(attr.Name);
Object value = Impromptu.InvokeConvert(attr.Value, pInfo.PropertyType); 
pInfo.SetValue(element, value, null);

答案 2 :(得分:1)

这可能只适用于基本类型,但它对我正在做的事情已经足够了

PropertyInfo pInfo = element.GetType().GetProperty(attr.Name);
Object value = System.Convert.ChangeType(attr.Value, pInfo.PropertyType);
pInfo.SetValue(element, value, null);