C # 5 से पहले, आपको फ़ॉरच के अंदर एक चर को फिर से घोषित करने की आवश्यकता है - अन्यथा यह साझा किया गया है, और आपके सभी हैंडलर अंतिम स्ट्रिंग का उपयोग करेंगे:
foreach (string list in lists)
{
string tmp = list;
Button btn = new Button();
btn.Click += new EventHandler(delegate { MessageBox.Show(tmp); });
}
गौरतलब है कि C # 5 के बाद से, यह बदल गया है, और विशेष रूप से के मामले मेंforeach
, आपको इसे और अधिक करने की आवश्यकता नहीं है: प्रश्न में कोड अपेक्षा के अनुरूप काम करेगा।
इस परिवर्तन के बिना काम न करने के लिए, निम्नलिखित पर विचार करें:
string[] names = { "Fred", "Barney", "Betty", "Wilma" };
using (Form form = new Form())
{
foreach (string name in names)
{
Button btn = new Button();
btn.Text = name;
btn.Click += delegate
{
MessageBox.Show(form, name);
};
btn.Dock = DockStyle.Top;
form.Controls.Add(btn);
}
Application.Run(form);
}
C # 5 से पहले ऊपर चलाएं , और यद्यपि प्रत्येक बटन एक अलग नाम दिखाता है, बटन पर क्लिक करने से "विल्मा" चार बार दिखाई देती है।
इसका कारण यह है कि भाषा की युक्ति (ECMA 334 v4, 15.8.4) (C # 5 से पहले) परिभाषित होती है:
foreach (V v in x)
embedded-statement
उसके बाद इसका विस्तार किया जाता है:
{
E e = ((C)(x)).GetEnumerator();
try {
V v;
while (e.MoveNext()) {
v = (V)(T)e.Current;
embedded-statement
}
}
finally {
… // Dispose e
}
}
ध्यान दें कि लूप के बाहर चर v
(जो आपका है list
) घोषित किया गया है। इसलिए कैप्चर किए गए चर के नियमों द्वारा, सूची के सभी पुनरावृत्तियों पर कब्जा किए गए चर धारक को साझा करेंगे।
C # 5 के बाद से, इसे बदल दिया जाता है: लूप के अंदर पुनरावृत्ति चर ( v
) स्कूप किया जाता है। मेरे पास एक विनिर्देश संदर्भ नहीं है, लेकिन यह मूल रूप से बन जाता है:
{
E e = ((C)(x)).GetEnumerator();
try {
while (e.MoveNext()) {
V v = (V)(T)e.Current;
embedded-statement
}
}
finally {
… // Dispose e
}
}
फिर से खोलना; यदि आप सक्रिय रूप से एक अनाम हैंडलर को अनसब्सक्राइब करना चाहते हैं, तो चाल को हैंडलर को स्वयं पकड़ना है:
EventHandler foo = delegate {...code...};
obj.SomeEvent += foo;
...
obj.SomeEvent -= foo;
इसी तरह, यदि आप एक बार केवल ईवेंट-हैंडलर चाहते हैं (जैसे लोड आदि):
EventHandler bar = null; // necessary for "definite assignment"
bar = delegate {
// ... code
obj.SomeEvent -= bar;
};
obj.SomeEvent += bar;
यह अब स्व-सदस्यता रद्द करना है;