8

我正在使用自定义属性来定义如何将类的成员映射到属性以作为表单发布(支付网关)发布。我的自定义属性工作得很好,并且能够通过“名称”获取属性,但想通过成员本身获取属性。

例如:

getFieldName("name");

对比

getFieldName(obj.Name);

计划是编写一个方法来将具有成员的类序列化为可发布的字符串。

这是我此时的测试代码,其中 ret 是一个字符串,PropertyMapping 是自定义属性:

foreach (MemberInfo i in (typeof(CustomClass)).GetMember("Name"))
{
    foreach (object at in i.GetCustomAttributes(true))
    {
        PropertyMapping map = at as PropertyMapping;
        if (map != null)
        {
            ret += map.FieldName;
        }
    }
}

提前致谢!

4

2 回答 2

9

您不能真正做到这一点,除非您使用的是 C# 3.0,在这种情况下您需要依赖 LINQ(嗯,表达式树)。

您所做的是为 lambda 表达式创建一个虚拟方法,让编译器生成表达式树(编译器进行类型检查)。然后你深入那棵树来获取成员。像这样:

static FieldInfo GetField<TType, TMemberType>(
    Expression<Func<TType, TMemberType>> accessor)
{
    var member = accessor.Body as MemberExpression;
    if (member != null)
    {
        return member.Member as FieldInfo;
    }
    return null; // or throw exception...
}

给定以下课程:

class MyClass
{
    public int a;
}

您可以像这样获取元数据:

// get FieldInfo of member 'a' in class 'MyClass'
var f = GetField((MyClass c) => c.a); 

通过对该字段的引用,您可以按照通常的方式挖掘任何属性。即反射。

static TAttribute GetAttribute<TAttribute>( 
    this MemberInfo member ) where TAttribute: Attribute
{
    return member.GetCustomAttributes( typeof( TAttribute ), false )
        .Cast<TAttribute>().FirstOrDefault<TAttribute>();
}

现在,您可以通过编译器大量检查的内容来挖掘任何字段的属性。它也适用于重构,如果您重命名“a”,Visual Studio 会捕捉到这一点。

var attr = GetField((MyClass c) => c.a).GetAttribute<DisplayNameAttribute>();
Console.WriteLine(attr.DisplayName);

那里的代码中没有一个文字字符串。

于 2009-03-10T14:18:34.757 回答
4

你可以更简单地做一半:

    foreach (PropertyMapping attrib in
        Attribute.GetCustomAttributes(i, typeof(PropertyMapping)))
    {
        ret += map.FieldName; // whatever you want this to do...
    }

顺便提一句; 你应该养成用单词结束属性的习惯Attribute。即使这会导致重复(参见 参考资料[XmlAttributeAttribute])。

然而——重新序列化;这并不总是微不足道的。大量的代码进入序列化框架,如 Json.NET 等。通常的方法可能是获取类型转换器,但在许多方面,使用PropertyDescriptor:

    foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(obj))
    {
        Console.WriteLine("{0}={1}",
            prop.Name, prop.Converter.ConvertToInvariantString(
                prop.GetValue(obj)));
    }
于 2009-03-10T14:16:22.547 回答