Comment définir la valeur d'un sélecteur de propriété Expression >

c# expression-trees linq

Question

J'ai besoin d'associer une propriété d'entité Address dans mon entité Person à l'expression linq dans ma classe FactoryEntities à l'aide d'une idée de fabrique de modèles, voici ce que j'ai et que je veux faire:

Address address = new Address();
address.Country = "Chile";
address.City = "Santiago";
address.ZipCode = "43532";
//Factory instance creation object
//This is idea
Person person = new FactoryEntity<Person>().AssociateWithEntity(p=>p.Address, address);

public class Person: Entity
{
    public string Name{ get; set; }
    public string LastName{ get; set; }
    public Address Address{ get; set; }
}

public class Address: Entity
{
    public string Country{ get; set; }
    public string City{ get; set; }
    public string ZipCode{ get; set; }
}

public class FactoryEntity<TEntity> where TEntity : Entity
{
    public void AssociateWithEntity<TProperty>(Expression<Func<TEntity, TProperty>> entityExpression, TProperty newValueEntity) where TProperty : Entity
    {
        if (instanceEntity == null || instanceEntity.IsTransient())
            throw new ArgumentNullException();

        /*TODO: Logic the association and validation 
        How set the newValueEntity into the property of entityExpression (x=>x.Direccion = direccion*/
    }
}

Réponse acceptée

Cela marche:

La méthode d'assistance suivante convertit une expression de lecture en un délégué de définition. Si vous souhaitez renvoyer une Expression<Action<T,TProperty>> au lieu d'une Action<T,TProperty> , n'appelez pas la méthode Compile() à la fin.

Remarque: le code provient du blog de Ian Mercer: http://blog.abodit.com/2011/09/convert-a-property-getter-to-a-setter/

    /// <summary>
    /// Convert a lambda expression for a getter into a setter
    /// </summary>
    public static Action<T, TProperty> GetSetter<T, TProperty>(Expression<Func<T, TProperty>> expression)
    {
        var memberExpression = (MemberExpression)expression.Body;
        var property = (PropertyInfo)memberExpression.Member;
        var setMethod = property.GetSetMethod();

        var parameterT = Expression.Parameter(typeof(T), "x");
        var parameterTProperty = Expression.Parameter(typeof(TProperty), "y");

        var newExpression =
            Expression.Lambda<Action<T, TProperty>>(
                Expression.Call(parameterT, setMethod, parameterTProperty),
                parameterT,
                parameterTProperty
            );

        return newExpression.Compile();
    }

Réponse populaire

Vous pouvez définir la propriété comme ceci:

public void AssociateWithEntity<TProperty>(
    Expression<Func<TEntity, TProperty>> entityExpression,
    TProperty newValueEntity)
    where TProperty : Entity
{
    if (instanceEntity == null)
        throw new ArgumentNullException();

    var memberExpression = (MemberExpression)entityExpression.Body;
    var property = (PropertyInfo)memberExpression.Member;

    property.SetValue(instanceEntity, newValueEntity, null);
}

Cela ne fonctionnera que pour les propriétés, pas pour les champs, bien que l’ajout de la prise en charge des champs soit facile.

Mais le code que vous avez pour obtenir la personne ne fonctionnera pas. Si vous souhaitez conserver le type de retour void de AssociateWithEntity() , vous pouvez le faire comme suit:

var factory = new FactoryEntity<Person>();
factory.AssociateWithEntity(p => p.Address, address);
Person person = factory.InstanceEntity;

Une autre option est une interface fluide:

Person person = new FactoryEntity<Person>()
    .AssociateWithEntity(p => p.Address, address)
    .InstanceEntity;



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi