2009-01-05 10 views
7

लैम्ब्डा अभिव्यक्तियों का एक लाभ यह है कि आपको केवल एक परिणाम का मूल्यांकन करना होगा जब आपको इसके परिणाम की आवश्यकता हो।सी # लैम्ब्डा अभिव्यक्ति और आलसी मूल्यांकन

निम्नलिखित (सरल) उदाहरण में, पाठ समारोह केवल मूल्यांकन किया जाता है जब एक लेखक मौजूद है:

public static void PrintLine(Func<string> text, TextWriter writer) 
{ 
    if (writer != null) 
    { 
     writer.WriteLine(text()); 
    } 
} 

दुर्भाग्य से, इस कोड का उपयोग कर एक छोटा सा बदसूरत बना देता है। आप की तरह

PrintLine("Some text", Console.Out); 

एक निरंतर या चर से कॉल करने और इसे इस तरह फोन करने की जरूरत नहीं कर सकते हैं:

PrintLine(() => "Some text", Console.Out); 

संकलक पारित कर दिया स्थिर से एक parameterless समारोह "का अनुमान लगा" करने में सक्षम नहीं है। क्या सी # के भविष्य के संस्करणों में इसे सुधारने की कोई योजना है या क्या मुझे कुछ याद आ रहा है?

अद्यतन:

मैं सिर्फ पाया एक गंदा अपने आप को हैक:

public class F<T> 
    { 
     private readonly T value; 
     private readonly Func<T> func; 

     public F(T value) { this.value = value; } 
     public F(Func<T> func) {this.func = func; } 

     public static implicit operator F<T>(T value) 
     { 
      return new F<T>(value); 
     } 

     public static implicit operator F<T>(Func<T> func) 
     { 
      return new F<T>(func); 
     } 

     public T Eval() 
     { 
      return this.func != null ? this.func() : this.value; 
     } 
} 

अब मैं बस के रूप में समारोह को परिभाषित कर सकते हैं:

public static void PrintLine(F<string> text, TextWriter writer) 
{ 
    if (writer != null) 
    { 
     writer.WriteLine(text.Eval()); 
    } 
} 

और यह दोनों एक समारोह या एक साथ फोन मूल्य।

उत्तर

1

वैसे वे दो कथन पूरी तरह से अलग हैं। एक कार्य को परिभाषित कर रहा है, जबकि दूसरा एक बयान है। वाक्यविन्यास को भ्रमित करना बहुत कठिन होगा।

() => "SomeText" //this is a function 

"SomeText" //this is a string 
+0

मैं सहमत हूं। एक अधिभार जोड़ने के मामले में, अंतर को बताना असंभव होगा [यदि ऐसा शॉर्टकट समर्थित था]। – Krisc

3

आप एक अधिभार इस्तेमाल कर सकते हैं: -

public static void PrintLine(string text, TextWriter writer) 
{ 
    PrintLine(() => text, writer); 
} 
+1

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

+0

इतना ही नहीं, आपको एन पैरामीटर के लिए 2^एन अधिभार बनाना होगा। – Rauhotz

+2

मुझे लगता है कि मैंने ओपी की जरूरत को गलत समझा। बाहर निकलता है, एक अधिभार जोड़ना वास्तव में सही काम हो सकता है, हालांकि मुझे लगता है कि मैं उन्हें उलट दूंगा (क्या कोई प्रतिनिधि प्रतिनिधि को लेता है, जो किसी अन्य तरीके के बजाय मूल्य लेता है)। –

1

आप स्ट्रिंग में यह गोंद के लिए पर एक विस्तार विधि लिख सकता है आप "कुछ पाठ" .PrintLine लिखने में सक्षम होना चाहिए (Console.Out।); और यह आपके लिए काम करता है।

विचित्र रूप से पर्याप्त, मैंने कुछ हफ्ते पहले और blogged about it here पर लैम्ब्डा अभिव्यक्तियों के आलसी मूल्यांकन के साथ कुछ खेला।

+2

आपके ब्लॉग में, आप कह रहे हैं कि कोई Func नहीं है। System.Action के बारे में क्या? – Rauhotz

1

संकलक प्रकार का निष्कर्ष निकालते पर बहुत अच्छा है, यह आशय का निष्कर्ष निकालते पर अच्छा नहीं है। सी # 3 में सभी नई वाक्य रचनात्मक चीनी के बारे में मुश्किल चीजों में से एक यह है कि वे भ्रम पैदा कर सकते हैं कि वास्तव में उनके साथ कंपाइलर क्या करता है।

() => "SomeText" 

संकलक यह देखता है और समझता है कि आप को उस अज्ञात फ़ंक्शन कोई पैरामीटर लेता है और System.String का एक प्रकार रिटर्न बनाने के लिए करना चाहते हैं:

अपने उदाहरण पर विचार करें। यह सब आपके द्वारा दिए गए लैम्ब्डा अभिव्यक्ति से अनुमानित है। हकीकत में अपने लैम्ब्डा इस का संकलन किया जाता है:

delegate { 
    return "SomeText"; 
}; 

और यह इस अनाम समारोह है कि आप निष्पादन के लिए PrintLine को भेज रहे हैं के लिए एक प्रतिनिधि है।

यह अतीत में हमेशा महत्वपूर्ण रहा है लेकिन अब LINQ, lambdas, iterator ब्लॉक, स्वचालित रूप से कार्यान्वित गुणों के साथ, अन्य चीजों के साथ .NET Reflector जैसे टूल का उपयोग करने के लिए अत्यंत महत्वपूर्ण है, इसके बाद अपना कोड देखने के लिए यह देखने के लिए संकलित किया गया है कि वास्तव में उन सुविधाओं को क्या काम करता है।

3

मुझे संदेह है कि सी # को यह सुविधा मिल जाएगी, लेकिन D में यह है। आपने जो रेखांकित किया है वह सी # में आलसी तर्क मूल्यांकन को लागू करने का एक उपयुक्त तरीका है, और शायद डी में lazy और अधिक शुद्ध कार्यात्मक भाषाओं में समान रूप से संकलित करता है।

सभी चीजों को माना जाता है, चार अतिरिक्त पात्र, प्लस वैकल्पिक सफेद स्थान स्पष्ट ओवरलोड रिज़ॉल्यूशन और बहु-प्रतिमान मजबूत-टाइप भाषा बनने में अभिव्यक्ति के लिए असाधारण रूप से बड़ी कीमत नहीं है।

2

दुर्भाग्य से, बदसूरत वाक्यविन्यास आपके पास सी # में है।

अद्यतन से "गंदा हैक" काम नहीं करता है, क्योंकि यह स्ट्रिंग पैरामीटर के मूल्यांकन में देरी नहीं करता है: operator F<T>(T value) पर जाने से पहले उनका मूल्यांकन किया जाता है।

PrintLine(() => string.Join(", ", names), myWriter) से PrintLine(string.Join(", ", names), myWriter) तुलना करें, पहले मामले में, स्ट्रिंग केवल तभी जुड़ जाएंगे जब वे मुद्रित हों; दूसरे मामले में, तारों में कोई फर्क नहीं पड़ता कि क्या: केवल प्रिंटिंग सशर्त है। दूसरे शब्दों में, मूल्यांकन बिल्कुल आलसी नहीं है।