2011-02-23 16 views
28

मैं संलग्न करने के लिए जहां विधेय और मेरा लक्ष्य के रूप में ही अभिव्यक्ति बनाने के लिए है की कोशिश कर रहा:मैं गतिशील रूप से अभिव्यक्ति कैसे बना सकता हूं <Func <MyClass, bool >> अभिव्यक्ति से भविष्यवाणी <Func <MyClass, string >>?

Services.Where(s => s.Name == "Modules" && s.Namespace == "Namespace"); 

मैं निम्नलिखित कोड है:

s => ((s.Name == "Modules") AndAlso (s.Namespace == "Namespace")) 
:

Expression<Func<Service,string>> sel1 = s => s.Name; 
Expression<Func<Service,string>> sel2 = s => s.Namespace; 

var val1 = Expression.Constant("Modules"); 
var val2 = Expression.Constant("Namespace"); 

Expression e1 = Expression.Equal(sel1.Body, val1); 
Expression e2 = Expression.Equal(sel2.Body, val2); 
var andExp = Expression.AndAlso(e1, e2); 

ParameterExpression argParam = Expression.Parameter(typeof(string), "s"); 
var lambda = Expression.Lambda<Func<string, bool>>(andExp, argParam); 

यह निम्न उत्पादन बनाने

हालांकि, यह के पैरामीटर के बाद से दोषपूर्ण है क्योंकि नाम और नेमस्पेस समान नहीं है। अगर मैं करने के लिए अभिव्यक्ति चयनकर्ता में से एक बदलने के लिए:

Expression<Func<Service,string>> sel2 = srv => srv.Namespace; 

उत्पादन होगा:

s => ((s.Name == "Modules") AndAlso (srv.Namespace == "Namespace")) 

मैं sel1 और sel2 के उपयोग के साथ एक वैध अभिव्यक्ति कैसे बना सकते हैं?

अद्यतन (28 फ़र, 2011)

मैं भाव आह्वान बनाने के द्वारा इसे हल:

Expression<Func<Service,string>> sel1 = s => s.Name; 
Expression<Func<Service,string>> sel2 = srv => srv.Namespace; 

var val1 = Expression.Constant("Modules"); 
var val2 = Expression.Constant("Namespace"); 

Expression<Func<Service, bool>> lambda = m => true; 
var modelParameter = lambda.Parameters.First(); 

// sel1 predicate 
{ 
    var invokedExpr = Expression.Invoke(sel1, modelParameter); 
    var binaryExpression = Expression.Equal(invokedExpr, val1); 
    lambda = Expression.Lambda<Func<Service, bool>>(Expression.AndAlso(binaryExpression, lambda.Body), lambda.Parameters); 
} 
// sel2 predicate 
{ 
    var invokedExpr = Expression.Invoke(sel2, modelParameter); 
    var binaryExpression = Expression.Equal(invokedExpr, val2); 
    lambda = Expression.Lambda<Func<Service, bool>>(Expression.AndAlso(binaryExpression, lambda.Body), lambda.Parameters); 
} 
+2

आप PredicateBuilder माना जाता है? यह विशेष रूप से "अनुमान लगाने की कोशिश कर रहा है" को हल करने के लिए डिज़ाइन किया गया है। http://www.albahari.com/nutshell/predicatebuilder.aspx –

+0

बहुत रोचक लगता है, मैं इसे देख लूंगा। धन्यवाद किर्क! –

उत्तर

53

यह है: Expression.Invoke इतना लैम्ब्डा भाव sel1 और sel2 एक MemberExpression होने के लिए आवश्यक नहीं है की जरूरत करना कंपाइलर-जेनरेटेड अभिव्यक्ति पेड़ और हाथ से बने लोगों को मिश्रण करना मुश्किल है, ठीक इसी तरह की चीज के कारण - पैरामीटर एक्सट्रेशंस निकालना मुश्किल है। तो चलो सिरे से शुरू करते हैं:

ParameterExpression argParam = Expression.Parameter(typeof(Service), "s"); 
Expression nameProperty = Expression.Property(argParam, "Name"); 
Expression namespaceProperty = Expression.Property(argParam, "Namespace"); 

var val1 = Expression.Constant("Modules"); 
var val2 = Expression.Constant("Namespace"); 

Expression e1 = Expression.Equal(nameProperty, val1); 
Expression e2 = Expression.Equal(namespaceProperty, val2); 
var andExp = Expression.AndAlso(e1, e2); 

var lambda = Expression.Lambda<Func<Service, bool>>(andExp, argParam); 

एक महत्वपूर्ण पहलू मैं बदल दिया है प्रकार Expression.Parameter को पारित कर दिया है - यह निश्चित रूप से लगता है कि उस Service बजाय एक string होना चाहिए।

मुझे लगता है कि एक कोशिश दे दिया है, और यह काम करने के लिए लग रहा था जब मैं lambda.Compile कहा जाता है और नमूना Service वस्तुओं के एक जोड़े पर यह मार डाला ...

+0

धन्यवाद जॉन! इसे अभी काम करने के लिए मिला। एसईएल 1 के सदस्य का नाम प्राप्त करना पूरी तरह से गलत होगा: ((सदस्य एक्स्पेरियन) sel1.Body) .Member.Name; आदि? –

+0

@ Torbjörn: उम, यह निर्भर करता है। मैं वास्तव में यह नहीं बता सकता कि आप क्या करने की कोशिश कर रहे हैं। यह स्पष्ट रूप से केवल तभी काम करेगा जब 'sel1' का शरीर वास्तव में * सदस्य 'एक्सप्रेशन' था ... और यह एक संपत्ति नहीं हो सकता है ... –

+0

यह 'अभिव्यक्ति' के अंदर 'ArgParam' को अनावश्यक रूप से गुजरता है। प्रॉपर्टी (ArgParam," नाम ") 'और' अभिव्यक्ति। लैम्ब्डा > (औरExp, argParam);'। मुझे लगता है कि आपको केवल 'अभिव्यक्ति' प्रॉपर्टी() '(दो गुणों के लिए) दोनों को पास करना पड़ा था, लेकिन हमें इसे फिर से अभिव्यक्ति 'लम्बाडा()' में क्यों पारित करने की आवश्यकता है? यह मेरे परिदृश्य के लिए वैसे भी काम करता था, मैं सिर्फ उत्सुक था;) – Alisson

संबंधित मुद्दे