Как я могу реализовать пользовательские атрибуты в .NET 2.0? - PullRequest
2 голосов
/ 05 ноября 2011

К сожалению, я все еще работаю на .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 ]

1 голос
/ 05 ноября 2011

Извините, вы не можете получить доступ к экземпляру класса или информации о свойствах внутри вашего атрибута. Вы должны написать дополнительный метод, например, статический метод в некотором «статическом» классе, который позволит вам делать то, что вы хотите.

Пример ....

    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));
    }

Предположим, мы поместили эти функции внутри атрибута. Затем мы хотим переопределить, например, наш метод ToString в нашем классе Customer.

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

Проблема в этом, конечно, в скорости, она использует отражение по имени, очень медленно, и рефакторинг, у вас не будет предупреждения или ошибки времени компиляции, если свойство "Имя" не существует, вы получите только исключение во время выполнения. Я бы предложил вам использовать другой механизм.

В более новой версии языка вы можете использовать лямбда-выражения для получения информации о свойстве непосредственно самим свойством, но, поскольку вы находитесь в C # 2.0, это невозможно.

Другое решение может быть следующим: добавить вместо этого другое свойство с именем FormattedXXX, например, FormattedName, которое возвращает длину по вашему желанию, и вы можете использовать это свойство вместо свойства Name. Это позволит вам сохранить отформатированную версию свойства рядом с вашей собственностью.

0 голосов
/ 05 ноября 2011

Вы должны сделать это наоборот. Вы не должны иметь никакой логики в своем атрибуте, он должен просто предоставлять свойства вместе с информацией, которую он содержит (например, свойство 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;
    }
}
...