Ho bisogno di associare un indirizzo di proprietà di entità nell'entità della classe Person con espressioni linq nella mia classe FactoryEntities usando l'idea di pattern factory, guarda questo è quello che ho e voglio fare:
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*/
}
}
Il seguente metodo di supporto converte un'espressione getter in un delegato setter. Se si desidera restituire Expression<Action<T,TProperty>>
invece di Action<T,TProperty>
, non chiamare il metodo Compile()
alla fine.
Nota: il codice è tratto dal blog di 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();
}
Puoi impostare la proprietà in questo modo:
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);
}
Questo funzionerà solo per le proprietà, non per i campi, sebbene l'aggiunta del supporto per i campi dovrebbe essere facile.
Ma il codice che hai per ottenere la persona non funzionerà. Se si desidera mantenere il tipo di restituzione void
di AssociateWithEntity()
, è possibile farlo in questo modo:
var factory = new FactoryEntity<Person>();
factory.AssociateWithEntity(p => p.Address, address);
Person person = factory.InstanceEntity;
Un'altra opzione è un'interfaccia fluente:
Person person = new FactoryEntity<Person>()
.AssociateWithEntity(p => p.Address, address)
.InstanceEntity;