2010-08-05 13 views
45

बाहरी परिवर्तनीय जाल वास्तव में क्या है? सी # में स्पष्टीकरण और उदाहरणों की सराहना की जाती है।बाहरी परिवर्तनीय जाल

संपादित करें: जॉन स्कीट का फरमान :) शामिल

Eric Lippert on the Outer Variable Trap

+3

मुझे नहीं पता था कि जब तक मैं इसे गुमराह नहीं करता तब तक आप किस बारे में बात कर रहे थे; ऐसा करने में, मुझे कई स्पष्टीकरण और उदाहरण मिले (सी # में), तो आप और क्या खोज रहे हैं? – Marc

+2

@Marc शायद ओपी उन लोगों में से एक है (निश्चित रूप से और अधिक है, कम से कम एक ने स्पष्ट रूप से कई बार कहा था) कि चाहते हैं कि प्रत्येक संभावित प्रासंगिक प्रोग्रामिंग प्रश्न के लिए एसओ का जवाब हो। इसके लिए उत्तर स्पष्ट रूप से गायब था। –

+1

@ मैसीज, उत्कृष्ट। मास्टर सूची पूरा होने के करीब एक कदम है! वेब प्रभुत्व, हम यहाँ आते हैं! – Marc

उत्तर

61

"बाहरी चर ट्रैप" तब होता है जब एक डेवलपर की उम्मीद है एक चर का मान एक लैम्ब्डा अभिव्यक्ति या अनाम प्रतिनिधि, जब वास्तव में द्वारा कब्जा कर लिया जा करने के लिए चर खुद को कब्जा कर लिया गया है।

उदाहरण:

var actions = new List<Action>(); 
for (var i = 0; i < 10; i++) 
{ 
    actions.Add(() => Console.Write("{0} ", i)); 
} 
foreach (var action in actions) 
{ 
    action(); 
} 

संभावित उत्पादन # 1:

0 1 2 3 4 5 6 7 8 9 

संभावित उत्पादन # 2:

10 10 10 10 10 10 10 10 10 10 

हैं आप आउटपुट # 1 की उम्मीद करते हैं, आप बाहरी परिवर्तनीय जाल में गिर गए हैं। आपको आउटपुट # 2 मिलता है।

फिक्स:

एक "आंतरिक चर" घोषित बार-बार "बाहरी चर" जो केवल एक बार कब्जा कर लिया है के बजाय कब्जा कर लिया जाना है।

var actions = new List<Action>(); 
for (var i = 0; i < 10; i++) 
{ 
    var j = i; 
    actions.Add(() => Console.Write("{0} ", j)); 
} 
foreach (var action in actions) 
{ 
    action(); 
} 

अधिक जानकारी के लिए, Eric Lippert's blog भी देखें।

+1

शब्द "जाल" पर दिलचस्प पन: चर (फंस गया), और आप एक समस्या से पकड़े गए हैं (एक जाल में गिर गए) –

+4

यह देखते हुए कि यह स्वीकार्य उत्तर बनने की संभावना है, एरिक लिपर्ट के ब्लॉग पोस्ट को जोड़ने का कोई मौका? http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-cononsidered-harmful.aspx –

+0

तो जे मूल रूप से एक 'ताजा' चर है, और इसलिए के-वें क्रिया में लूप वैरिएबल द्वारा मानी गई के-वें मान से जुड़ा एक चर j_k होता है। नतीजतन अपेक्षित व्यवहार प्राप्त किया जाता है। –

4

कुछ की तरह

foreach (var s in strings) 
    var x = results.Where(r => (r.Text).Contains(s)); 

परिणाम आप उम्मीद कर रहे हैं, क्योंकि इसमें शामिल प्रत्येक यात्रा के लिए मार डाला नहीं है नहीं कर सकेगा। लूप के अंदर एक अस्थायी चर को असाइन करने से यह ठीक हो जाएगा।

+0

मैं 'var =' वाक्यविन्यास से परिचित नहीं हूं, वह क्या करता है? = पी – Marc

+0

नाइटपिक: प्रत्येक समावेशन के लिए 'युक्त' निष्पादित किया जाता है, लेकिन आश्चर्यजनक रूप से हमेशा एक ही मूल्य होगा। – dtb

+0

@ डीटीबी @ मर्क हाँ, क्या डीटीबी ने कहा। मैं शायद यह अच्छी तरह से समझा नहीं रहा हूँ। var केवल रिटर्न प्रकार को स्पष्ट रूप से घोषित करने का एक विकल्प है (वास्तविक कोड में मैं वास्तव में यहां वापसी प्रकार घोषित करता हूं लेकिन मैं एक आईडीई के सामने नहीं हूं और वास्तव में जहां वास्तव में लौटता हूं उसे देखकर ऐसा नहीं लगता ... मुझे लगता है इसकी आईनंबरबल <>) – heisenberg

1

@ डीटीबी सही (बड़ा +1) है, लेकिन यह ध्यान रखना महत्वपूर्ण है कि यह केवल तब लागू होता है जब बंद होने का दायरा लूप के बाहर फैलता है। उदाहरण के लिए:

var objects = new [] 
    { 
     new { Name = "Bill", Id = 1 }, 
     new { Name = "Bob", Id = 5 }, 
     new { Name = "David", Id = 9 } 
    }; 

for (var i = 0; i < 10; i++) 
{ 
    var match = objects.SingleOrDefault(x => x.Id == i); 

    if (match != null) 
    { 
     Console.WriteLine("i: {0} match: {1}", i, match.Name); 
    } 
} 

यह प्रिंट होगा:

i: 1 match: Bill 
i: 5 match: Bob 
i: 9 match: David

ReSharper जो सुरक्षित रूप से इस मामले में अनदेखा किया जा सकता "संशोधित बंद, तक पहुंच" के बारे में चेतावनी देगा।

0

यह लेख बंद की अवधारणा को समझाने उपयोगी है:

http://en.wikipedia.org/wiki/Closure_(computer_science)

इसके अलावा, इस लेख एक अधिक विशिष्ट सी # कार्यान्वयन से वास्तव में अच्छा है: वैसे भी

http://blogs.msdn.com/b/abhinaba/archive/2005/08/08/448939.aspx

, tl ; lr यह वैरिएबल स्कोप अज्ञात प्रतिनिधि या लैम्ब्डा अभिव्यक्तियों में उतना ही महत्वपूर्ण है जितना कि यह आपके कोड के भीतर कहीं और है - व्यवहार सिर्फ उतना स्पष्ट नहीं है।

0

यह ध्यान रखें कि इस जाल भी लेकिन has been changed अर्थात अब करीब हर बार पाश चर की ताज़ा प्रति अधिक foreach छोरों के लिए ही अस्तित्व के बाद से सी # 5.0, foreach छोरों बंद अंदर योग्य है। तो नीचे दिए गए कोड:

var values = new List<int>() { 100, 110, 120 }; 
var funcs = new List<Func<int>>(); 
foreach (var v in values) 
    funcs.Add(() => v); 
foreach (var f in funcs) 
    Console.WriteLine(f()); 

प्रिंटों 120 120 120< सी # 5.0, लेकिन 100 110 120> = सी # 5,0

हालांकि for छोरों अभी भी उसी तरह व्यवहार करते हैं।