4 votes

Obtenir la valeur par défaut d'une propriété en fonction de son nom

J'ai une propriété (exemple ci-dessous).

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

La situation dans laquelle je l'utilise est de m'assurer qu'il apparaisse en tant que en gras dans une PropertyGrid si la valeur par défaut n'est pas définie.

Je trouve incroyablement ennuyeux que dans mon constructeur, je doive définir la valeur initiale de ma propriété, et espérer qu'elles correspondent.

Est-il possible de faire en sorte que mon constructeur "découvre" la valeur par défaut d'une propriété donnée, et la définisse en conséquence ? Quelque chose comme :

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

8voto

Tragedian Points 12308

Vous pouvez utiliser le code suivant pour obtenir les métadonnées que vous recherchez.

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

Si vous voulez faire quelque chose realmente cool, vous pouvez le faire avec une expression Lambda :

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

L'usage est alors :

myctor()
{
   myVal = GetDefaultValue(x => x.MyProperty);
}

5voto

SLaks Points 391154

Vous pouvez appeler le GetProperty pour trouver la propriété, puis appeler GetCustomAttributes(typeof(DefaultValueAttribute) (et couler son résultat) pour que l'attribut soit appliqué.

0voto

Ruud Lenders Points 674

Voici une méthode d'extension générique basée sur la réponse de Paul Turner. Elle fonctionnera pour n'importe quel membre de n'importe quelle classe.

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

Sinon, si vous êtes d'accord pour que la valeur par défaut soit renvoyée si l'attribut n'est pas trouvé, utilisez ceci :

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

Vous pourriez également le modifier pour qu'il lève une exception si l'attribut n'est pas trouvé.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X