如何在.NET 2.0中实现自定义属性?

时间:2011-11-05 08:43:31

标签: c# .net .net-2.0 custom-attributes

不幸的是我仍然在研究.NET 2.0。我之前没有创建过自定义属性。 我想创建一个CustomStringFormatAttribute:。

如果一个类,比如Customer.Name,则具有:

MaxLength=30
ActualLength=10

我需要用空格填充它直到它达到30。

我还需要一个日期属性,我可以格式化DisplayDataFormat

我创建了以下内容但如何访问属性中属性的实际值?

public class Customer
{
    [CustomStringFormatAttribute(30)]
    public string Name { get; set; }

    //todo:customDateAttribute
    public DateTime StartDate { get; set; }
}

[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
public sealed class CustomStringFormatAttribute : Attribute
{
    private readonly int maxLength;

    public CustomStringFormatAttribute(int maxLength)
    {
       MaxLength = maxLength;
    }

    public  int MaxLength { get; private set; }

    //?Should I override ToString 
    public override string ToString()
    {
        return Format();
    }

    private string Format()
    {
        //simplified version of my formatting for brevity
        string source = "value from the property of the class.";//How do I get access to the actual value of the property within the attribute?
        const char paddingChar = ' ';
        return source.PadLeft(maxLength, paddingChar);
    }    
}

有什么建议吗?

注意:为了简洁起见,我使用了自动属性。我在.NET 2.0中没那么奢侈。

2 个答案:

答案 0 :(得分:1)

抱歉,您无法访问属性中的类实例或属性信息。 您应该编写一个额外的方法,例如某个“静态”类中的静态方法,它允许您执行您想要执行的操作。

实施例...

    public static string FormatProperty(object instance, PropertyInfo property)
    {
        CustomStringFormatAttribute attrib = Attribute.GetCustomAttribute(property, typeof(CustomStringFormatAttribute)) as CustomStringFormatAttribute;
        return property.GetValue(instance, null).ToString().PadLeft(attrib.MaxLength, ' ');
    }

    public static string FormatProperty(object instance, string propertyName)
    {
        return FormatProperty(instance, instance.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance));
    }

但是,由于使用反射通过财产信息获取财产价值,这非常令人不舒服并且非常缓慢。

要访问属性属性,您需要PropertyInfo。

    public static int GetPropertyMaxLength(PropertyInfo property)
    {
        CustomStringFormatAttribute attrib = Attribute.GetCustomAttribute(property, typeof(CustomStringFormatAttribute)) as CustomStringFormatAttribute;
        return attrib != null ? attrib.MaxLength : int.MaxValue;
    }

    public static int GetPropertyMaxLength(Type type, string propertyName)
    {
        return GetPropertyMaxLength(type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance));
    }

假设我们将这些函数放在属性中。 然后我们想要覆盖我们的Customer类中的ToString方法。

public override string ToString()
{
    return CustomStringFormatAttribute.FormatProperty(this, "Name");
}

这个问题当然是速度,它使用名称反射,非常慢,重构,如果属性“名称”不存在,你将没有编译时警告或错误,你只会得到一个例外在运行时。我建议你使用另一种机制。

使用较新版本的语言,您可以使用lambda表达式直接通过属性本身获取属性信息,但由于您使用的是C#2.0,因此无法实现。

另一种解决方案可以是:添加另一个名为FormattedXXX的属性,例如FormattedName,它可以根据需要返回长度,您可以使用该属性而不是Name属性。 这样您就可以将属性的格式化版本保留在您的财产附近。

答案 1 :(得分:0)

你需要反过来做。您的属性中不应该有任何逻辑,它应该只使用它包含的信息公开属性(例如MaxLength属性)。然后,您的Customer班级应该访问CustomStringFormatAttribute提供的信息并对其进行相应格式化:

private string m_Name;

public string Name
{
    get
    {
        var formatAttribute = typeof(Customer).GetCustomAttributes(false)
                                  .OfType<CustomStringFormatAttribute>
                                  .SingleOrDefault();

        if (formatAttribute != null)
            return m_Name.PadLeft(formatAttribute.MaxLength);

        return m_Name;
    }
    set
    {
        m_Name = value;
    }
}