Получить значение свойства по умолчанию с учетом его имени

У меня есть свойство (пример показан ниже).

 [DefaultValue(false)]
 public bool MyProperty {
    get {
       return myVal;
    }
    set {
       myVal=value;
    }
 }

Ситуация, которую я использую, заключается в том, чтобы убедиться, что он отображается как полужирный в PropertyGrid, если значение по умолчанию не установлено.

Меня невероятно раздражает, что в моем конструкторе я должен установить начальное значение моего свойства и надеюсь, что они совпадают.

Возможно ли, чтобы мой конструктор «обнаружил» значение по умолчанию для данного свойства и установил его соответствующим образом? Что-то типа:

myctor()
{
   myVal = GetDefaultValueProperty<bool>("MyProperty");
}

person greggorob64    schedule 20.05.2011    source источник


Ответы (3)


Вы можете использовать следующий код, чтобы получить нужные вам метаданные.

public static T GetDefaultValue<T>(string propertyName)
{
    var property = typeof(MyClass).GetProperty(propertyName);

    var attribute = property
        .GetCustomAttribute(typeof(DefaultValueAttribute)) 
            as DefaultValueAttribute;

    if(attribute != null)
    {
        return (T)attribute.Value;
    }
}

Если вы хотите сделать что-то действительно классное, вы можете сделать это с помощью лямбда-выражения:

public static T GetDefaultValue<T>(
    Expression<Func<T, MyClass>> propertySelector)
{
    MemberExpression memberExpression = null;

    switch (expression.Body.NodeType)
    {
        case ExpressionType.MemberAccess:
            // This is the default case where the 
            // expression is simply member access.
            memberExpression 
                = expression.Body as MemberExpression;
            break;

        case ExpressionType.Convert:
            // This case deals with conversions that 
            // may have occured due to typing.
            UnaryExpression unaryExpression 
                = expression.Body as UnaryExpression;

            if (unaryExpression != null)
            {
                memberExpression 
                    = unaryExpression.Operand as MemberExpression;
            }
            break;
    }


    MemberInfo member = memberExpression.Member;

    // Check for field and property types. 
    // All other types are not supported by attribute model.
    switch (member.MemberType)
    {
        case MemberTypes.Property:
            break;
        default:
            throw new Exception("Member is not property");
    }

    var property = (PropertyInfo)member;

    var attribute = property
        .GetCustomAttribute(typeof(DefaultValueAttribute)) 
            as DefaultValueAttribute;

    if(attribute != null)
    {
        return (T)attribute.Value;
    }
}

Тогда использование:

myctor()
{
   myVal = GetDefaultValue(x => x.MyProperty);
}
person Paul Turner    schedule 20.05.2011

Вы можете вызвать метод GetProperty, чтобы найти свойство, затем вызвать GetCustomAttributes(typeof(DefaultValueAttribute) (и привести его результат), чтобы применить атрибут.

person SLaks    schedule 20.05.2011

Вот общий метод расширения, основанный на ответе Пола Тернера. Это будет работать для любого члена любого класса.

public static bool TryGetDefaultValue<TSource, TResult>(this TSource _, Expression<Func<TSource, TResult>> expression, out TResult result)
{
    if (((MemberExpression)expression.Body).Member.GetCustomAttribute(typeof(DefaultValueAttribute)) is DefaultValueAttribute attribute)
    {
        result = (TResult)attribute.Value;
        return true;
    }

    result = default;
    return false;
}

В качестве альтернативы, вы в порядке с возвращаемым значением по умолчанию, если атрибут не был найден, используйте это:

public static TResult GetDefaultValue<TSource, TResult>(this TSource _, Expression<Func<TSource, TResult>> expression)
{
    if (((MemberExpression)expression.Body).Member.GetCustomAttribute(typeof(DefaultValueAttribute)) is DefaultValueAttribute attribute)
    {
        return (TResult)attribute.Value;
    }

    return default;
}

Вы также можете изменить его, чтобы генерировать исключение, если атрибут не найден.

person Rudey    schedule 18.02.2020