이 검사를 통해 눈에 띄게 보이는 것보다 더 많은 폐쇄 값이 포착되고 있다는 사실에주의를 기울여야합니다. 이는 이러한 값의 수명에 영향을 미칩니다.
다음 코드를 고려하십시오.
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 # 컴파일러의 구현 세부 사항 때문입니다. 컴파일 중에 클로저는 캡처 된 값을 보유하는 필드와 클로저 자체를 나타내는 메소드가있는 클래스로 다시 작성됩니다. 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가 강조하고있는 "암시 적"캡처입니다.
이 검사의 의미는 암시 적으로 캡처 된 클로저 값이 클로저 자체가 가비지 수집 될 때까지 가비지 수집되지 않는다는 것입니다. 이 값의 수명은 이제 값을 명시 적으로 사용하지 않는 클로저의 수명과 연결됩니다. 클로저가 오래 지속되는 경우, 특히 캡처 된 값이 매우 큰 경우 코드에 부정적인 영향을 줄 수 있습니다.
이것은 컴파일러의 구현 세부 사항이지만 Microsoft (Roslyn 이전 및 이후) 또는 Mono의 컴파일러와 같은 버전과 구현에서 일관성이 있습니다. 값 유형을 캡처하는 여러 클로저를 올바르게 처리하려면 구현이 설명 된대로 작동해야합니다. 예를 들어, 여러 클로저가 int를 캡처하는 경우 동일한 인스턴스를 캡처해야합니다.이 인스턴스는 단일 공유 개인 중첩 클래스에서만 발생할 수 있습니다. 이것의 부작용은 모든 캡처 된 값의 수명이 이제 모든 값을 캡처하는 모든 클로저의 최대 수명이라는 것입니다.