यह निरीक्षण इस तथ्य की ओर आपका ध्यान आकर्षित करता है कि स्पष्ट रूप से देखने की तुलना में अधिक करीबी मूल्यों पर कब्जा किया जा रहा है, जिसका इन मूल्यों के जीवनकाल पर प्रभाव पड़ता है।
निम्नलिखित कोड पर विचार करें:
using System;
public class Class1 {
private Action _someAction;
public void Method() {
var obj1 = new object();
var obj2 = new object();
_someAction += () => {
Console.WriteLine(obj1);
Console.WriteLine(obj2);
};
// "Implicitly captured closure: obj2"
_someAction += () => {
Console.WriteLine(obj1);
};
}
}
पहले क्लोजर में, हम देखते हैं कि obj1 और obj2 दोनों को स्पष्ट रूप से कैप्चर किया जा रहा है; हम इसे केवल कोड को देखकर देख सकते हैं। दूसरे बंद के लिए, हम देख सकते हैं कि obj1 को स्पष्ट रूप से कैप्चर किया जा रहा है, लेकिन ReSharper हमें चेतावनी दे रहा है कि obj2 को अंतर्निहित रूप से कैप्चर किया जा रहा है।
यह सी # कंपाइलर में कार्यान्वयन विस्तार के कारण है। संकलन के दौरान, क्लोज़र उन फ़ील्ड्स के साथ वर्गों में फिर से लिखे जाते हैं जो कैप्चर किए गए मानों को रखते हैं, और वे विधियाँ जो क्लोजर को दर्शाती हैं। C # कंपाइलर केवल एक ऐसी निजी क्लास प्रति मेथड बनाएगा, और यदि एक से अधिक क्लोजर को एक विधि में परिभाषित किया जाता है, तो इस क्लास में कई तरीके होंगे, प्रत्येक क्लोजर के लिए एक, और इसमें सभी क्लोजर से सभी कैप्चर किए गए मान भी शामिल होंगे।
यदि हम उस कोड को देखते हैं जो संकलक उत्पन्न करता है, तो यह थोड़ा सा दिखता है (कुछ नामों को पढ़ने में आसानी के लिए साफ किया गया है):
public class Class1 {
[CompilerGenerated]
private sealed class <>c__DisplayClass1_0
{
public object obj1;
public object obj2;
internal void <Method>b__0()
{
Console.WriteLine(obj1);
Console.WriteLine(obj2);
}
internal void <Method>b__1()
{
Console.WriteLine(obj1);
}
}
private Action _someAction;
public void Method()
{
// Create the display class - just one class for both closures
var dc = new Class1.<>c__DisplayClass1_0();
// Capture the closure values as fields on the display class
dc.obj1 = new object();
dc.obj2 = new object();
// Add the display class methods as closure values
_someAction += new Action(dc.<Method>b__0);
_someAction += new Action(dc.<Method>b__1);
}
}
जब विधि चलती है, तो यह डिस्प्ले क्लास बनाता है, जो सभी मूल्यों को कैप्चर करता है, सभी क्लोजर के लिए। यहां तक कि अगर किसी एक क्लोजर में मूल्य का उपयोग नहीं किया जाता है, तो भी इसे कैप्चर किया जाएगा। यह "निहित" कैप्चर है जिसे ReSharper हाइलाइट कर रहा है।
इस निरीक्षण का निहितार्थ यह है कि अनुमानित रूप से कब्जा कर लिया गया क्लोजर मूल्य तब तक कचरा एकत्र नहीं किया जाएगा, जब तक कि क्लोजर स्वयं कचरा एकत्र न हो जाए। इस मूल्य का जीवनकाल अब एक बंद के जीवनकाल से जुड़ा हुआ है जो मूल्य का स्पष्ट रूप से उपयोग नहीं करता है। यदि क्लोजर लंबे समय तक रहता है, तो इससे आपके कोड पर नकारात्मक प्रभाव पड़ सकता है, खासकर यदि कैप्चर किया गया मूल्य बहुत बड़ा है।
ध्यान दें कि यह कंपाइलर का क्रियान्वयन विवरण है, यह माइक्रोसॉफ्ट और (रोसलिन के बाद के संस्करण) या मोनो के कंपाइलर जैसे संस्करणों और कार्यान्वयनों के अनुरूप है। मूल्य प्रकार कैप्चर करने वाले कई क्लोजर को सही ढंग से संभालने के लिए कार्यान्वयन को वर्णित के रूप में काम करना चाहिए। उदाहरण के लिए, यदि कई क्लोज़र एक इंट को कैप्चर करते हैं, तो उन्हें उसी उदाहरण को कैप्चर करना होगा, जो केवल एक साझा निजी नेस्टेड वर्ग के साथ हो सकता है। इसका दुष्प्रभाव यह है कि सभी कैप्चर किए गए मूल्यों का जीवनकाल अब किसी भी क्लोजर का अधिकतम जीवनकाल है जो किसी भी मूल्य को पकड़ता है।