Cómo establecer valor una propiedad selector de expresión >

c# expression-trees linq

Pregunta

Necesito asociar una propiedad de entidad. Dirección en mi clase de persona. Entidad con expresiones linq en mi clase de FactoryEntities usando la idea de patrón de fábrica. Mira, esto es lo que tengo y quiero hacer:

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*/
    }
}

Respuesta aceptada

Esto funciona:

El siguiente método auxiliar convierte una expresión de obtención en un delegado de establecimiento. Si desea devolver una Expression<Action<T,TProperty>> lugar de una Action<T,TProperty> , simplemente no llame al método Compile() al final.

Nota: El código es del 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();
    }

Respuesta popular

Puede establecer la propiedad de esta manera:

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

Esto funcionará solo para las propiedades, no para los campos, aunque agregar soporte para los campos debería ser fácil.

Pero el código que tienes para conseguir que la persona no funcione. Si desea mantener el tipo de retorno void de AssociateWithEntity() , puede hacerlo así:

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

Otra opción es una interfaz fluida:

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


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow