2010-11-09 10 views
5

इस कोड स्निपेट पर विचार करें और इतने विस्तार विधि द्वारा दिए गए मान के प्रतिलिपि है अनुमान लगाना क्या y1 और y2ये दो कार्य समान मूल्य क्यों नहीं लौटाते हैं?

static class Extensions 
{ 
    public static Func<T> AsDelegate<T>(this T value) 
    { 
     return() => value; 
    } 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     new Program(); 
    } 

    Program() 
    { 
     double x = Math.PI; 

     Func<double> ff = x.AsDelegate(); 
     Func<double> fg =() => x; 

     x = -Math.PI; 

     double y1 = ff(); // y1 = 3.141.. 
     double y2 = fg(); // y2 = -3.141.. 

    } 
} 

आप कह सकते हैं -Aha- डबल एक मूल्य के प्रकार है और करने के लिए मूल्यांकन की कोशिश मुख्य x। लेकिन जब आप उपरोक्त वर्गों के प्रतिनिधियों में बदलते हैं तो परिणाम अभी भी अलग हैं। उदाहरण:

class Foo 
{ 
    public double x; 
} 
    Program() 
    { 
     Foo foo = new Foo() { x=1.0 }; 

     Func<Foo> ff = foo.AsDelegate(); 
     Func<Foo> fg =() => foo; 

     foo = new Foo() { x = -1.0 }; 

     double y1 = ff().x; // y1 = 1.0 
     double y2 = fg().x; // y2 = -1.0 
    } 

तो दोनों कार्यों को एक ही कक्षा के दो अलग-अलग उदाहरण लौटाएंगे। यह मानना ​​दिलचस्प है कि ff() स्थानीय चर के संदर्भ में foo का संदर्भ देता है, लेकिन fg() नहीं है और यह वर्तमान में इस क्षेत्र में निर्भर करता है।

तो क्या होता है जब इन दो प्रतिनिधियों को कोड के अन्य हिस्सों में भेज दिया जाता है, जिनके पास foo उदाहरण की दृश्यता नहीं है? किसी भी तरह का सवाल है कि किस प्रकार का सूचना है (डेटा) कम और कम स्पष्ट हो रहा है जब विस्तार विधियों को प्रतिनिधियों के साथ जोड़ा जाता है।

उत्तर

3

ff इस लाइन पर कैप्चर (बांध) x की मूल्य रहे हैं:

Func<double> ff = x.AsDelegate(); 

इसके विपरीत, fg इस लाइन पर चरx को बांधता है:

Func<double> fg =() => x; 

तो , जब x परिवर्तनों का मान, ff अप्रभावित है, लेकिन fg परिवर्तन।

+0

ब्रेवटी + स्पष्टता + प्रारूप के कारण इस उत्तर को उत्तर दें। – ja72

+0

मेह ... यह एक है: किसी भी चीज़ के * मूल्य * से बंधे नहीं है (कंपाइलर-कैप्चर क्लास इंस्टेंस उत्पन्न करता है) को छोड़कर, और बी: सख्ती से "x" * से बाध्य नहीं है * - स्पष्ट हां, लेकिन मुझे लगता है कि उस सादगी के कारण शायद थोड़ा भ्रामक लगता है। (सादगी अच्छी है हालांकि) –

+0

@Marc - यह एक टॉस अप है। मैंने इसे लागू करने के तरीके में गोता लगाने के बजाए किसी उपयोगकर्ता को दिखाई देने के तरीके पर ध्यान केंद्रित करने का अनुमान लगाया। – Bevan

2

() => x एक्स मान कैप्चर करता है। लैम्ब्डा या अज्ञात प्रतिनिधियों को संभालने के लिए कंपाइलर द्वारा विशेष कक्षा बनाई जाती है, लैम्बडा में उपयोग किए जाने वाले किसी भी चर को कैद किया जाता है।

उदाहरण के लिए यदि आप कोड निम्नलिखित चलाएँ:

List<Func<int>> list = new List<Func<int>>(); 

    for (int i = 0; i < 5; i++) 
    { 
     list.Add(() => i); 
    } 

    list.ForEach(function => Console.WriteLine(function())); 

आपको लगता है कि मुद्रित संख्या ही कर रहे हैं देखेंगे।

+0

तो जब फ़ंक्शन() कहा जाता है तो उस समय मेरे पास जो भी मूल्य है (लूप के बाहर) का उपयोग करता है? मैंने सोचा कि लूप समाप्त होने पर 'i' का दायरा समाप्त होता है ... – ja72

7

AsDelegate, चर value (AsDelegate के पैरामीटर) है जबकि () => x कब्जा चर x। तो यदि आप x का मान बदलते हैं, तो लैम्ब्डा अभिव्यक्ति एक अलग मान लौटाएगी। x बदलना value बदलता नहीं है।

देखें: Outer Variable Trap

+0

कड़ाई से बोलते हुए यह * तर्क * मान को कैप्चर करता है; जिसका मूल्य प्रारंभ में एक्स का मान है, और कभी नहीं बदला जाता है। एक सूक्ष्म भेद ... –

3

AsDelegate विस्तार विधि समय AsDelegate पर x के मान का उपयोग करता है, जबकि लैम्ब्डा अभिव्यक्ति () => x चर x और इसलिए x का मूल्य समय अभिव्यक्ति शुरू हो जाती है (बजाय मूल्य जब यह पर लिया जाता है कब्जा कहा जाता है परिभाषित किया गया था)।

4

AsDelegate में, हम "मूल्य" तर्क को कैप्चर कर रहे हैं। इस तर्क का मूल्य वैरिएबल के मूल्य की प्रतिलिपि के रूप में लिया जाता है जब विधि लागू की जाती है, और कभी भी परिवर्तन नहीं होता - इसलिए हम मूल वस्तु देखते हैं।

प्रत्यक्ष लैम्ब्डा कब्जा चर foo (नहीं मूल्य चर के - चर ही) - इस प्रकार हम यह करने के लिए परिवर्तन देखने कर

असल में एक विधि कॉल जोड़ने से जांघ को पकड़ा गया।

0

पहली विधि किसी दिए गए फ़ंक्शन में नए प्रतिनिधि बनाता है और इसे स्टोर करता है। बाद में आप foo को ओवरराइट करते हैं, आपके नव निर्मित प्रतिनिधि को छुआ नहीं जाता है।

दूसरा एक एक लैम्ब्डा अभिव्यक्ति जो लिफ्टों/* कब्जा * उसके संदर्भ, foo चर मतलब यह है कि है। लैम्बडा अभिव्यक्तियों द्वारा उठाए गए चरों में सभी परिवर्तन उस लैम्ब्डा अभिव्यक्ति द्वारा देखे जाते हैं।

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