web-dev-qa-db-fra.com

Comment définir la valeur d'une propriété à l'aide d'expressions?

Étant donné la méthode suivante:

public static void SetPropertyValue(object target, string propName, object value)
{
    var propInfo = target.GetType().GetProperty(propName,
                         BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);

    if (propInfo == null)
        throw new ArgumentOutOfRangeException("propName", "Property not found on target");
    else
        propInfo.SetValue(target, value, null);
}

Comment feriez-vous pour écrire son équivalent activé par l'expression sans avoir besoin de passer un paramètre supplémentaire pour la cible?

Pourquoi faire cela au lieu de définir la propriété directement, je vous entends dire. Par exemple, supposons que nous ayons la classe suivante avec une propriété qui a un getter public mais un setter privé:

public class Customer 
{
   public string Title {get; private set;}
   public string Name {get; set;}
}

Je voudrais pouvoir appeler:

var myCustomerInstance = new Customer();
SetPropertyValue<Customer>(cust => myCustomerInstance.Title, "Mr");

Voici maintenant un exemple de code.

public static void SetPropertyValue<T>(Expression<Func<T, Object>> memberLamda , object value)
{
    MemberExpression memberSelectorExpression;
    var selectorExpression = memberLamda.Body;
    var castExpression = selectorExpression as UnaryExpression;

    if (castExpression != null)
        memberSelectorExpression = castExpression.Operand as MemberExpression;
    else
        memberSelectorExpression = memberLamda.Body as MemberExpression;

    // How do I get the value of myCustomerInstance so that I can invoke SetValue passing it in as a param? Is it possible

}

Des pointeurs?

59
Anastasiosyal

Vous pouvez tricher et vous simplifier la vie avec une méthode d'extension:

public static class LambdaExtensions
{
    public static void SetPropertyValue<T, TValue>(this T target, Expression<Func<T, TValue>> memberLamda, TValue value)
    {
        var memberSelectorExpression = memberLamda.Body as MemberExpression;
        if (memberSelectorExpression != null)
        {
            var property = memberSelectorExpression.Member as PropertyInfo;
            if (property != null)
            {
                property.SetValue(target, value, null);
            }
        }
    }
}

et alors:

var myCustomerInstance = new Customer();
myCustomerInstance.SetPropertyValue(c => c.Title, "Mr");

La raison pour laquelle cela est plus facile est que vous avez déjà la cible sur laquelle la méthode d'extension est invoquée. L'expression lambda est également une expression de membre simple sans fermeture. Dans votre exemple d'origine, la cible est capturée dans une fermeture et il pourrait être un peu difficile d'atteindre la cible sous-jacente et PropertyInfo.

119
Darin Dimitrov