0

我正在尝试使用反射来设置某些 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”->“JustificationValues”)派生的便利事实。不过,我仍然很好奇在一般情况下如何解决这个问题。

Edit2:GetGenericArguments 让我走完了剩下的路。谢谢。

4

3 回答 3

4

如果属性值只是一个字符串,我假设您已经有某种方法可以确定该字符串标识了来自特定枚举的值。在您的示例中,您对其进行了硬编码,因此我不确定这是您想要的还是您想要更改的。

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

现在,如果我假设EnumValue<T>有一个带有T.

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

现在concreteType是类型EnumValue<JustificationValues>

从那里你可以得到一个构造函数,希望是一个带有JustificationValues参数的构造函数,并且Invoke它。

更新

啊,我明白你现在在做什么。您使用 XML 属性名称来选择 C# 属性。您需要能够检测该属性是否属于 type 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...

试试看。

于 2009-07-20T17:58:25.123 回答
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);
于 2011-04-18T15:40:53.607 回答
1

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

PropertyInfo pInfo = element.GetType().GetProperty(attr.Name);
Object value = System.Convert.ChangeType(attr.Value, pInfo.PropertyType);
pInfo.SetValue(element, value, null);
于 2011-05-17T05:25:46.587 回答