2011-08-28 14 views
14

मैं सी # में अभिव्यक्ति पेड़ सीख रहा हूं।स्थानीय चर और अभिव्यक्ति पेड़

मैं थोड़ी देर के लिए अब अटक कर रहा हूँ:

string filterString = "ruby"; 
Expression<Func<string, bool>> expression = x => x == filterString; 

मैं कोड द्वारा इस अभिव्यक्ति कैसे निर्माण कर सकते हैं? स्थानीय चर को कैप्चर करने का कोई नमूना नहीं है। यह एक आसान है:

Expression<Func<string, bool>> expression = x => x == "ruby"; 

यह होगा:

ParameterExpression stringParam = Expression.Parameter(typeof(string), "x"); 
Expression constant = Expression.Constant("ruby"); 
BinaryExpression equals = Expression.Equal(stringParam, constant); 
Expression<Func<string, bool>> lambda1 = 
    Expression.Lambda<Func<string, bool>>(
     equals, 
     new ParameterExpression[] { stringParam }); 

डिबगर प्रिंट के लिए (x => x == filterString) निम्नलिखित:

{x => (एक्स == मूल्य (Predicate.Program + <> c__DisplayClass3) .filterString)}

इस विषय पर कुछ प्रकाश डालने के लिए धन्यवाद।

उत्तर

24

स्थानीय चर को कैप्चर करना वास्तव में स्थानीय चर को "होस्टिंग" द्वारा उदाहरण एक कंपाइलर-जेनरेटेड क्लास के चर में किया जाता है। सी # कंपाइलर उचित समय पर अतिरिक्त कक्षा का एक नया उदाहरण बनाता है, और प्रासंगिक चर में आवृत्ति चर के उपयोग में स्थानीय चर के किसी भी पहुंच को बदलता है।

तो अभिव्यक्ति वृक्ष को उदाहरण के भीतर फ़ील्ड एक्सेस होना आवश्यक है - और उदाहरण स्वयं ConstantExpression के माध्यम से प्रदान किया जाता है।

अभिव्यक्ति पेड़ों को बनाने के तरीके के लिए काम करने के लिए सबसे आसान तरीका आम तौर पर लैम्ब्डा अभिव्यक्ति में कुछ समान बनाना है, फिर परावर्तक में जेनरेट कोड को देखें, ऑप्टिमाइज़ेशन स्तर को नीचे चालू करें ताकि प्रतिबिंबक इसे वापस लैम्ब्डा में परिवर्तित न कर सके भाव।

+2

धन्यवाद। उत्पन्न एमएसआईएल कोड को देखने का संकेत बहुत उपयोगी है। – yonexbat

+3

कुछ 'var hoistedConstant = Expression.Property (Expression.Constant (new {value = filterString}), "Value") की तरह कुछ; ' – Appetere

+1

@Appetere' Expression.Constant (filterString) 'के बारे में क्या करना चाहिए? माना जाता है कि यह चर में परिवर्तन को प्रतिबिंबित नहीं करेगा, लेकिन न ही आपका सुझाव होगा। –

5

यह कोड एक बंदरगाह ब्लॉक में अभिव्यक्ति को लपेटता है जो स्थानीय चर को स्थिर के रूप में मानता है।

string filterString = "ruby"; 

var filterStringParam = Expression.Parameter(typeof(string), "filterString"); 
var stringParam = Expression.Parameter(typeof(string), "x"); 

var block = Expression.Block(
// Add a local variable. 
new[] { filterStringParam }, 
// Assign a constant to the local variable: filterStringParam = filterString 
Expression.Assign(filterStringParam, Expression.Constant(filterString, typeof(string))), 
// Compare the parameter to the local variable 
Expression.Equal(stringParam, filterStringParam)); 

var x = Expression.Lambda<Func<string, bool>>(block, stringParam).Compile(); 
0

एक पुरानी सवाल, लेकिन जब Linq करने वाली संस्थाओं (L2E) के लिए कुछ इसी तरह के निर्माण भाव करने के लिए है कि मामले में आप Expression.Block उपयोग नहीं कर सकते के रूप में यह एसक्यूएल करने के लिए नीचे पार्स नहीं किया जा सकता है की कोशिश कर रहा मैं इसे करने के लिए आया था।

जॉन के उत्तर के बाद यह एक स्पष्ट उदाहरण है जो एल 2 ई के साथ काम करेगा। एक सहायक कक्षा बनाएं फिल्टर का मान होना चाहिए:

class ExpressionScopedVariables 
{ 
    public String Value; 
} 

बिल्ड पेड़ इस प्रकार:

var scope = new ExpressionScopedVariables { Value = filterString}; 
var filterStringExp = Expression.Constant(scope); 
var getVariable = typeof(ExpressionScopedVariables).GetMember("Value")[0]; 
var access = Expression.MakeMemberAccess(filterStringExp, getVariable); 

और फिर सदस्य पहुँच अभिव्यक्ति के साथ मूल कोड में लगातार बदल देते हैं:

BinaryExpression equals = Expression.Equal(stringParam, access); 
Expression<Func<string, bool>> lambda1 = 
    Expression.Lambda<Func<string, bool>>(
     equals, 
     new ParameterExpression[] { stringParam }); 
संबंधित मुद्दे