2011-11-12 31 views
18

Model fabrikası fikrini kullanarak FactoryEntities sınıfımdaki ifadeler linq ile bir kişilik özellik varlık benim bir varlık özellik adresi ilişkilendirmek gerekir, bak bu benim sahip olduğum ve yapmak istiyorum: Özellik değeri Açıklama <Func <a1><T,TResult>>

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

Orada var olan 'propertyInfo' bir 'TProperty' değil, 'TEntity' içindir. Farklı türde bir nesne için bir özelliğe erişmek için kullanamazsınız. Dernek hangi yoldan gitmeli? Burada yapmaya çalıştığınız şey bana mantıklı gelmiyor. –

+0

Çok buggy kodu ve ne istediğinizi söylemek kolay değil, açıklığa kavuşturun. –

+0

Açıklama açık olmadığı için özür dilerim ama yapmak istediğim bir fabrika işgal etmek için izin veren bir fabrika işgal etmektir, bu nedenle düzgün bir şekilde –

cevap

23

Bu işler:

aşağıdaki yardımcı

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

Başka bir seçenek de akıcı arayüz yöntem, bir alıcı ifadesini bir ayarlayıcı delegeye dönüştürür. Action<T,TProperty> yerine bir Expression<Action<T,TProperty>> döndürmek istiyorsanız, en sonunda Compile() yöntemini arama.

Not: kod Ian Mercer blogdan geçerli: Fikir i dikkate svick katkısını alarak, bu kod ile benim için çalıştı ediyorum oluyor 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(); 
    } 
+0

Nasıl çalışıyorsunuz? Bu method? Delegeye doğru argümanları alamıyorum. –

+1

@hbob, bir şey gibi: 'GetSetter ((string örnek) => example.Length)' – smartcaveman

+1

TProperty'yi bilmiyorsanız nasıl olur? Expression.Lambda > kullanma çalışmıyor :( – markmnl

5

böyle özelliği ayarlayabilirsiniz:

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

Bu özellikler değil, alanlar için yalnızca çalışacak, alanlar için destek ekleyerek kolay olmalıdır rağmen.

Ancak kişiyi almak için sahip olduğunuz kod çalışmaz. Eğer AssociateWithEntity() ait void dönüş türü tutmak istiyorsanız, bunu şöyle yapabiliriz:

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

:

bana geçerli bir

yılında Kişi nesneyi inşa etmek için Buraya
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); 
    } 
} 

ben fabrika aramak

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

Ama bu kodun en iyi olup olmadığını bilmiyorum, en azından compile() yöntemini çağırmadım, ne diyorsunuz?

sayesinde

2

Başka bir çözüm mülk sahibi karınca yansıma kullanarak özellik ayarlayıcı çağırmak elde etmektir. herhangi yaptığım

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); 
+0

'lambda.Body' UnaryExpression' olabilir, bkz http://stackoverflow.com/soru/12420466 yapamaz /-için-cast-nesnenin t ype-sistem-linq-ifadeler-unaryexpression-to-tipi – xmedeko

0

tip karışık Rytis I çözüm ve https://stackoverflow.com/a/12423256/254109

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

Ve ile çağrı uzatma yöntemleri kullanmaz ve olabilir Bu çözümün avantajı onu

SetPropertyValue(() => myStuff.MyProp, newValue); 
çağrı
İlgili konular