Можно ли добавить метод расширения к свойству класса, чтобы получить значение атрибута, связанного со свойством? - PullRequest
5 голосов
/ 12 августа 2011

У меня есть несколько классов с присвоенными им атрибутами. Больше всего меня интересует значение FieldLength.MaxLength.

/// <summary>
/// Users
/// </summary>
[Table(Schema = "dbo", Name = "users"), Serializable]
public partial class Users
{

    /// <summary>
    /// Last name
    /// </summary>
    [Column(Name = "last_name", SqlDbType = SqlDbType.VarChar)]
    private string _LastName;
    [FieldLength(MaxLength=25), FieldNullable(IsNullable=false)]
    public string LastName
    {
        set { _LastName = value; }
        get { return _LastName; }
    }

}

Мне нужно знать, можно ли написать какой-нибудь метод расширения для свойств в моем классе, чтобы он возвращал значение MaxLength атрибута FieldLength?

Например. Я хотел бы иметь возможность написать что-то вроде следующего ...

Users user = new Users();
int lastNameMaxLength = user.LastName.MaxLength();

Ответы [ 5 ]

2 голосов
/ 12 августа 2011

Чтобы сохранить набор текста, вы можете дополнительно уточнить расширение Джейсона до чего-то подобного.

public static void MaxLength<T>(this T obj, Expression<Func<T, object>> property)

Таким образом, он будет отображаться на всех объектах (если вы не укажете ограничение where T), и у вас будет безопасная реализация Property Access во время компиляции, как если бы вы использовали код как:

user.MaxLength(u => u.LastName);
2 голосов
/ 12 августа 2011

Нет, это невозможно.Вы можете добавить метод расширения на Users, хотя:

public static int LastNameMaxLength(this Users user) {
    // get by reflection, return
}
0 голосов
/ 12 августа 2011

Это невозможно в такой форме. Лучшее, чем вы можете управлять, - это метод, который принимает лямбда-выражение, получает связанное с ним свойство и затем использует отражение для получения атрибута.

int GetMaxLength<T>(Expression<Func<T,string>> property);

И назовите это как:

GetMaxLength<Users>((u)=>LastName)
0 голосов
/ 12 августа 2011

Вы могли бы написать метод расширения, но он должен был бы принять первый параметр PropertyInfo, а не string (поскольку сам string не имеет атрибутов.) Это выглядело бы примерно так:

public static int GetMaxLength(this PropertyInfo prop)
{
    // TODO: null check on prop
    var attributes = prop.GetCustomeAttributes(typeof(FieldLengthAttribute), false);
    if (attributes != null && attributes.Length > 0)
    {
        MaxLengthAttribute mla = (MaxLengthAttribute)attributes[0];
        return mla.MaxLength;
    }

    // Either throw or return an indicator that something is wrong
}

После этого вы получаете собственность через отражение:

int maxLength = typeof(Users).GetProperty("LastName").GetMaxLength();
0 голосов
/ 12 августа 2011

Нет.Поскольку предлагаемый синтаксис возвращает значение свойства LastName, а не само свойство.

Чтобы извлечь и использовать атрибуты, вам необходимо использовать отражение, что означает, что вам нужно знатьсамо свойство.

Как идея, вы могли бы достичь этого аккуратно с помощью библиотеки выражений LINQ, хотя и разрешить свойство для объекта.

Пример синтаксиса, который вы можете искать:

var lastNameMaxLength = AttributeResolver.MaxLength<Users>(u => u.LastName);

Где:

public class AttributeResolver
{
    public int MaxLength<T>(Expression<Func<T, object>> propertyExpression)
    {
        // Do the good stuff to get the PropertyInfo from the Expression...
        // Then get the attribute from the PropertyInfo
        // Then read the value from the attribute
    }
}

Этот класс оказался полезным для разрешения свойств из выражений:

public class TypeHelper
{
    private static PropertyInfo GetPropertyInternal(LambdaExpression p)
    {
        MemberExpression memberExpression;

        if (p.Body is UnaryExpression)
        {
            UnaryExpression ue = (UnaryExpression)p.Body;
            memberExpression = (MemberExpression)ue.Operand;
        }
        else
        {
            memberExpression = (MemberExpression)p.Body;
        }
        return (PropertyInfo)(memberExpression).Member;
    }

    public static PropertyInfo GetProperty<TObject>(Expression<Func<TObject, object>> p)
    {
        return GetPropertyInternal(p);
    }
}
...