类成员的自定义属性

时间:2009-03-10 14:06:59

标签: c# reflection attributes custom-attributes

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

例如:

getFieldName("name");

VS

getFieldName(obj.Name);

计划是编写一个方法,将带有成员的类序列化为一个postable字符串。

这是我此时的测试代码,其中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;
        }
    }
}

提前致谢!

2 个答案:

答案 0 :(得分:9)

你不能真的这样做,除非你使用的是C#3.0,在这种情况下你需要依赖LINQ(ehm,表达式树)。

你所做的是为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);

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

答案 1 :(得分: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)));
    }