Подтвердить что ты не робот

Как заданное значение: селектор свойств Expression <Func <T, TResult >>

Мне нужно связать свойство объекта entity в объекте класса Person с выражением linq в моем классе FactoryEntities с использованием шаблона factory, посмотрите, что у меня есть, и я хочу сделать:

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

Ответ 1

Это работает:

Следующий вспомогательный метод преобразует выражение-геттер в делегат сеттера. Если вы хотите вернуть Expression<Action<T,TProperty>> вместо Action<T,TProperty>, просто не вызывайте метод Compile() в конце.

Примечание: Код из блога 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();
    }

Ответ 2

Вы можете установить свойство следующим образом:

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

Это будет работать только для свойств, а не для полей, хотя добавление поддержки полей должно быть легким.

Но код, который у вас есть для получения человека, не будет работать. Если вы хотите сохранить возвращаемый тип void AssociateWithEntity(), вы можете сделать это следующим образом:

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

Другим вариантом является свободный интерфейс:

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

Ответ 3

Другим решением является получение владельцем собственности ant invoke set setter с использованием отражения. Преимущество этого решения в том, что он не использует методы расширения и может быть вызван любым типом

private void SetPropertyValue(Expression<Func<object, object>> lambda, object value)
{
    var memberExpression = (MemberExpression)lambda.Body;
    var propertyInfo = (PropertyInfo)memberExpression.Member;
    var propertyOwnerExpression = (MemberExpression)memberExpression.Expression;
    var propertyOwner = Expression.Lambda(propertyOwnerExpression).Compile().DynamicInvoke();

    propertyInfo.SetValue(propertyOwner, value, null);            
}
...
SetPropertyValue(s => myStuff.MyPropy, newValue);

Ответ 4

Что идея, я работаю для меня с этим кодом, принимая во внимание вклад svick:

public class FactoryEntity<TEntity> where TEntity : Entity, new()

{

private TEntity _Entity;

    public FactoryEntity()
    {
        _Entity = new TEntity();
    }

public TEntity Build()
    {
        if (_Entity.IsValid())
            throw new Exception("_Entity.Id");

        return _Entity;
    }

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

        SetObjectValue<TEntity, TProperty>(_Entity, foreignEntity, instanceEntity);
        return this;
    }

private void SetObjectValue<T, TResult>(object target, Expression<Func<T, TResult>> expression, TResult value)
    {
        var memberExpression = (MemberExpression)expression.Body;
        var propertyInfo = (PropertyInfo)memberExpression.Member;
        var newValue = Convert.ChangeType(value, value.GetType());
        propertyInfo.SetValue(target, newValue, null);
    }
}

Здесь я вызываю factory для меня, чтобы создать объект Person в действительном

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

Но я не знаю, является ли этот код оптимальным или нет, по крайней мере, я не вызываю метод compile(), что говорят?

спасибо

Ответ 5

Я сделал смешанное решение Rytis I и fooobar.com/info/121612/...

private static void SetPropertyValue<T>(Expression<Func<T>> lambda, object value)
    {
        var memberExpression = (MemberExpression)lambda.Body;
        var propertyInfo = (PropertyInfo)memberExpression.Member;
        var propertyOwnerExpression = (MemberExpression)memberExpression.Expression;
        var propertyOwner = Expression.Lambda(propertyOwnerExpression).Compile().DynamicInvoke();

        propertyInfo.SetValue(propertyOwner, value, null);
    }

И назовите его

SetPropertyValue(() => myStuff.MyProp, newValue);