Bu inceleme, dikkatinizi açıkça görülebilenden daha fazla kapatma değerinin yakalandığına dikkat çeker ve bu da bu değerlerin kullanım ömrünü etkiler.
Aşağıdaki kodu göz önünde bulundurun:
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);
};
}
}
İlk kapanışta, hem obj1 hem de obj2'nin açıkça yakalandığını görüyoruz; bunu sadece koda bakarak görebiliriz. İkinci kapanış için obj1'in açıkça yakalandığını görebiliriz, ancak ReSharper bize obj2'nin örtük olarak yakalandığını bildiriyor.
Bunun nedeni C # derleyicisindeki bir uygulama ayrıntısıdır. Derleme sırasında, kapanışlar, yakalanan değerleri tutan alanlarla ve kapamanın kendisini temsil eden yöntemlerle sınıflara yeniden yazılır. C # derleyicisi, yöntem başına yalnızca bir tane özel sınıf oluşturur ve bir yöntemde birden çok kapatma tanımlanırsa, bu sınıf, her bir kapatma için bir tane olmak üzere birden çok yöntem içerir ve ayrıca tüm kapanmalardan elde edilen tüm değerleri içerir.
Derleyicinin oluşturduğu koda bakarsak, buna biraz benziyor (okuma kolaylaştırmak için bazı isimler temizlendi):
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);
}
}
Yöntem çalıştığında, tüm kapaklar için tüm değerleri yakalayan display sınıfını oluşturur. Bu nedenle, kapaklardan birinde bir değer kullanılmasa bile, yine de yakalanır. Bu, ReSharper'ın vurguladığı "örtük" yakalamadır.
Bu incelemenin sonucu, örtük olarak yakalanan kapatma değerinin, kapağın kendisi çöp toplanana kadar toplanmayacağıdır. Bu değerin ömrü, değeri açıkça kullanmayan bir kapağın ömrüne bağlanmıştır. Kapatma uzun ömürlü ise, özellikle yakalanan değer çok büyükse, kodunuz üzerinde olumsuz bir etkisi olabilir.
Bu, derleyicinin bir uygulama ayrıntısı olsa da, Microsoft (Roslyn öncesi ve sonrası) veya Mono'nun derleyicisi gibi sürümler ve uygulamalar arasında tutarlı olduğunu unutmayın. Değer türünü yakalayan birden çok kapağı doğru bir şekilde işlemek için uygulamanın açıklandığı gibi çalışması gerekir. Örneğin, birden çok kapatma bir int yakalarsa, aynı örneği yakalamaları gerekir; bu, yalnızca tek bir paylaşılan özel iç içe sınıfla gerçekleşebilir. Bunun yan etkisi, yakalanan tüm değerlerin ömrünün, artık değerlerden herhangi birini yakalayan herhangi bir kapağın maksimum ömrü olmasıdır.