2010-01-12 11 views
9

कुछ दिनों के लिए अभिव्यक्ति पेड़ के साथ मेरे काम के दौरान, मैं कुछ ऐसा हुआ जो मुझे समझना मुश्किल लगता है; उम्मीद है कि कोई यहां कुछ प्रकाश डालेगा।अभिव्यक्ति कैसे बनाएं <Func <गतिशील, गतिशील >> - या यह एक बग है?

यदि आप Expression<Func<dynamic, dynamic>> expr1 = x => 2 * x; कोड करते हैं तो संकलक शिकायत करेगा और आपको कहीं भी नहीं मिलेगा। हालांकि, यह लगता है कि यदि आप किसी विधि के माध्यम से ऐसी एक अभिव्यक्ति बनाते हैं तो संकलक इसके बारे में खुश दिखता है और परिणामी ऐप काम करता है। यह समझ में नहीं आता है, इसलिए मैं सोच रहा हूं कि पर्दे के पीछे क्या चल रहा है।

मुझे लगता है कि, हुड के नीचे, अभिव्यक्ति ConvertExpression द्वारा लौटाए प्रकार Expression<Func<object, object>> है, जो एक मान्य प्रकार है की शायद है, लेकिन यह पहेली मुझे लगता है कि मैं एक घोषणा में Expression<Func<dynamic, dynamic>> प्रकार का उपयोग नहीं कर सकते हैं और अभी तक मैं इसे उपयोग कर सकते हैं एक विधि के वापसी प्रकार के रूप में। नीचे एक उदाहरण देखें।

बहुत बहुत धन्यवाद!

public class ExpressionExample 
{ 
    public void Main() 
    { 
     // Doesn't compile: 
     //Expression<Func<dynamic, dynamic>> expr1 = x => 2 * x; 

     // Compiles and works - OK 
     Expression<Func<double, double>> expr2 = x => 2 * x; 
     Func<double, double> func2 = (Func<double, double>)expr2.Compile(); 
     Console.WriteLine(func2(5.0).ToString()); // Outputs 10 

     // Compiles and works - ??? This is the confusing block... 
     Expression<Func<dynamic, dynamic>> expr3 = ConvertExpression(expr2); 
     Func<dynamic, dynamic> func3 = (Func<dynamic, dynamic>)expr3.Compile(); 
     Console.WriteLine(func3(5.0).ToString()); // Outputs 10 

     // Side note: compiles and works: 
     Expression<Func<object, object>> expr4 = x => double.Parse(2.ToString()) * double.Parse(x.ToString()); 
     Func<object, object> func4 = (Func<object, object>)expr4.Compile(); 
     Console.WriteLine(func4(5.0).ToString()); // Outputs 10 
    } 

    private Expression<Func<dynamic, dynamic>> ConvertExpression<TInput, TOutput>(Expression<Func<TInput, TOutput>> expression) 
    { 
     Expression<Func<object, TInput>> convertToInput = value => (TInput)value; 
     // The following doesn't compile: var input = Expression.Parameter(typeof(dynamic), "input"); 

     var input = Expression.Parameter(typeof(object), "input");   

     Expression<Func<TOutput, dynamic>> convertToOutput = value => (dynamic)value; 

     var body = Expression.Invoke(convertToOutput, Expression.Invoke(expression, Expression.Invoke(convertToInput, input))); 
     var lambda = Expression.Lambda<Func<dynamic, dynamic>>(body, input); 

     return lambda; 
    } 
} 
+0

अभिव्यक्ति पेड़ में गतिशीलता - समाधान यहां: [http://stackoverflow.com/questions/3562088/c-4- गतिशील-in-expression-trees ](httpoverflow.com/questions/3562088/c -4-गतिशील-इन-अभिव्यक्ति-पेड़) –

उत्तर

13

मुझे लगता है कि, हुड के नीचे, अभिव्यक्ति ConvertExpression द्वारा लौटाए प्रकार Expression<Func<object, object>> की शायद है, जो एक मान्य प्रकार

सही है।

मैं घोषणा में Expression<Func<dynamic, dynamic>> प्रकार का उपयोग नहीं कर सकता और फिर भी मैं इसे विधि के रिटर्न प्रकार के रूप में उपयोग कर सकता हूं।

कथन का यह हिस्सा गलत है। जैसा कि आप अपने उदाहरण में नोट करते हैं, स्थानीय चर की घोषणा में उस प्रकार का उपयोग करना पूरी तरह कानूनी है।

जो बिट कानूनी नहीं है वह लैम्बडा के अंदर गतिशील संचालन का निष्पादन है जिसे अभिव्यक्ति वृक्ष प्रकार में परिवर्तित किया जा रहा है। विशिष्ट अभिव्यक्ति वृक्ष प्रकार अप्रासंगिक है; क्या मायने रखता है कि ऑपरेशन गतिशील है।

+0

उत्तर और टिप्पणी के लिए बहुत बहुत धन्यवाद - यह हल करता है! –

+0

@Eric मूल रूप से वहाँ है (अभी भी?) Lambdas के अंदर गतिशील संचालन के लिए कोई समर्थन नहीं है। क्या कभी ऐसा होगा? – Maghis

+1

@ मैगी: स्टैक ओवरव्लो उन प्रश्नों के लिए एक बुरी जगह है जहां भविष्य की भविष्यवाणी की आवश्यकता होती है। हमारे पास ऐसी सुविधा के लिए अब कोई योजना नहीं है; चाहे हम अगले बीस वर्षों में, मुझे कैसे पता होना चाहिए? –

3

संकलक त्रुटि मुझे मिल गया जब मैं अपने कोड की कोशिश की थी "त्रुटि CS1963: एक अभिव्यक्ति पेड़ एक गतिशील आपरेशन शामिल नहीं हो सकता"। मैंने समस्या रेखा को Expression<Func<dynamic, dynamic>> expr1 = x => x; में बदल दिया (लैम्बडा से "ऑपरेशन" को हटा दिया) और यह काम किया! इसलिए आपको अभिव्यक्तियों में गतिशीलता की अनुमति है, लेकिन आप वास्तव में उन पर "संचालन" नहीं कर सकते हैं। बहुत उपयोगी नहीं, मुझे पता है। मेरे परीक्षण में, .ToString() एक ऑपरेशन के रूप में गिना जाता है।

+0

धन्यवाद - मैं वही देखता हूं ... इससे चीजों को और भी विचित्र लगता है - इसलिए, यदि कुछ ऑपरेशन हैं, तो यह संकलित नहीं होता है। हालांकि, अगर कोई नहीं है, तो यह संकलित करता है। क्या यह रनटाइम पर गतिशील प्रकार के संकल्प संचालन, विधि आमंत्रण इत्यादि के पीछे दर्शन का विरोध नहीं करता है? –

+2

संकुचन समय पर उन गतिशील संचालन के लिए उत्पन्न कोडजन जो रनटाइम पर गतिशील अर्थशास्त्र लागू करता है वह बहुत जटिल है; पर्याप्त जटिल है कि अभिव्यक्ति वृक्ष में इसे स्पष्ट रूप से प्रस्तुत करने का कोई आसान तरीका नहीं है। असल में, पसंद "अभिव्यक्ति पेड़ में उन्हें अनुमति न दें", या "देर से जहाज", या "जहाज छोटी गाड़ी" के लिए नीचे आ गया। हमने पूर्व को चुना। यदि पर्याप्त मांग है तो हम इसे भविष्य के संस्करणों में हमेशा एक सुविधा के रूप में जोड़ सकते हैं; यदि आप इस सुविधा को प्रेरित करने वाले आकर्षक उपयोगकर्ता परिदृश्यों का वर्णन कर सकते हैं, तो यह सुविधा कार्य के बजट के समय आने में मदद करेगा। –

+0

यदि कोई इस पर एक कनेक्ट पोस्ट खोलता है तो मैं इसके लिए वोट दूंगा। –

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