2011-11-12 10 views
18

मुझे पैटर्न फैक्ट्री विचार का उपयोग करके मेरी फैक्ट्रीएन्टिटीज क्लास में अभिव्यक्ति linq के साथ मेरी व्यक्तिगत श्रेणी इकाई में एक इकाई संपत्ति पता संबद्ध करने की आवश्यकता है, यह मेरे पास है और मैं यह करना चाहता हूं:एक संपत्ति चयनकर्ता अभिव्यक्ति का मूल्य कैसे निर्धारित करें <Func <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

आपके पास 'propertyInfo' है जो' TENTITY' के लिए है, न कि 'टीप्रोपर्टी'। आप किसी भिन्न प्रकार की ऑब्जेक्ट के लिए किसी प्रॉपर्टी तक पहुंचने के लिए इसका उपयोग नहीं कर सकते हैं। एसोसिएशन किस तरह से जाना जाता है? आप जो करने की कोशिश कर रहे हैं वह मुझे समझ में नहीं आता है। –

+0

यह बहुत छोटी गाड़ी कोड है, और यह आसान नहीं है कि आप जो चाहते हैं उसे स्पष्ट करें। –

+0

मुझे खेद है कि स्पष्टीकरण स्पष्ट नहीं था, लेकिन मैं ऐसा करना चाहता हूं जो एक फैक्ट्री पर कब्जा करने के लिए है जो मुझे ऑब्जेक्ट को एसोसिएशन को मान्य करने में हस्तक्षेप करने की अनुमति देता है, इसलिए यह उचित रूप से –

उत्तर

23

यह काम करता है::

निम्नलिखित सहायक

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

एक अन्य विकल्प एक धाराप्रवाह इंटरफ़ेस है विधि एक गेटर अभिव्यक्ति को एक सेटर प्रतिनिधि में बदल देती है। यदि आप Action<T,TProperty> के बजाय Expression<Action<T,TProperty>> वापस करना चाहते हैं, तो अंत में Compile() विधि को कॉल न करें।

नोट: कोड इयान मर्सर की ब्लॉग से है: 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

आप कैसे कॉल करते हैं यह विधि? मुझे प्रतिनिधि में सही तर्क नहीं मिल रहा है। –

+1

@ hbob, कुछ ऐसा: 'GetSetter ((स्ट्रिंग उदाहरण) => उदाहरण। लम्बाई) ' – smartcaveman

+1

यदि आप टीप्रोपर्टी को नहीं जानते हैं तो कैसे? अभिव्यक्ति का उपयोग करना। लैम्ब्डा <एक्शन > काम नहीं करता है :( – markmnl

5

आप इस तरह गुण सेट कर सकते हैं:

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

यह गुण, नहीं क्षेत्रों के लिए ही काम करते हैं, हालांकि क्षेत्रों के लिए समर्थन जोड़ने आसान होना चाहिए।

लेकिन आपके पास व्यक्ति को प्राप्त करने के लिए कोड काम नहीं करेगा। आप AssociateWithEntity() की void वापसी प्रकार रखना चाहते हैं, तो आप इसे इस तरह कर सकता है:

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

है विचार है, मैं इस कोड के साथ मेरे लिए काम किया कर रहा हूँ कि, खाते में 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); 
    } 
} 

यहाँ मैं कारखाने फोन मुझे एक वैध

में व्यक्ति वस्तु का निर्माण करने के लिए
Person person = new FactoryEntity<Person>().AssociateWithEntity(p=>p.Address, address).Build(); 

लेकिन मुझे नहीं पता कि यह कोड इष्टतम है या नहीं, कम से कम मैं संकलित() विधि को कॉल करने के लिए कॉल नहीं करता, क्या कह रहा है?

धन्यवाद

2

एक अन्य समाधान संपत्ति के मालिक चींटी प्रतिबिंब का उपयोग आह्वान संपत्ति सेटर प्राप्त करने के लिए है। इस समाधान है कि यह विस्तार तरीकों का उपयोग नहीं करता है और हो सकता है किसी भी प्रकार

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 'हो सकता है, http://stackoverflow.com देखें/प्रश्न/12420466/असमर्थ करने वाली कच्चे वस्तु के- टी ype-प्रणाली-LINQ-भाव-unaryexpression-टू-प्रकार – xmedeko

0

मैं बनाया है मिश्रित Rytis I समाधान और 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); 
    } 

और साथ फोन का लाभ यह

SetPropertyValue(() => myStuff.MyProp, newValue); 
फोन