UFO ET IT

Resharper : 암시 적으로 캡처 된 클로저 :이

ufoet 2020. 11. 18. 21:50
반응형

Resharper : 암시 적으로 캡처 된 클로저 :이


Resharper에서이 경고 ( "Implicity captured Closure : this")를 받고 있습니다. 이것은이 코드가 전체를 둘러싼 객체를 캡처한다는 의미입니까?

    internal Timer Timeout = new Timer
                            {
                                Enabled = false,
                                AutoReset = false
                            };
    public Task<Response> ResponseTask
    {
        get
        {
            var tcs = new TaskCompletionSource<Response>();

            Timeout.Elapsed += (e, a) => tcs.SetException(new TimeoutException("Timeout at " + a.SignalTime));

            if (_response != null) tcs.SetResult(_response);
            else ResponseHandler += r => tcs.SetResult(_response);
            return tcs.Task;
        }
    }

어떻게 또는 왜 그렇게하는지 잘 모르겠습니다. 캡처해야하는 유일한 변수는 의도적 인 TaskCompletionSource입니다. 이것이 실제로 문제입니까? 그렇다면 어떻게 해결해야합니까?

편집 : 경고는 첫 번째 람다 (Timeout 이벤트)에 있습니다.


문제는 내가 생각하는 선이 아닌 것 같습니다.

문제는 부모 개체의 필드를 참조하는 두 개의 람다가 있다는 것입니다. 컴파일러는 두 개의 메서드와 부모 클래스 ( this)에 대한 참조로 클래스를 생성합니다 .

에 대한 참조 this가 잠재적으로 TaskCompletionSource 개체에 남아있어 GC 가되지 않기 때문에 이것이 문제가 될 것이라고 생각합니다 . 적어도 그것이 내가이 문제에서 찾은 것이 암시하는 바입니다.

생성 된 클래스는 다음과 같습니다 (분명히 이름이 다르고 발음 할 수 없습니다).

class GeneratedClass {
    Request _this;
    TaskCompletionSource tcs;

    public lambda1 (Object e, ElapsedEventArgs a) {
        tcs.SetException(new TimeoutException("Timeout at " + a.SignalTime));
    }

    public lambda2 () {
        tcs.SetResult(_this._response);
    }
}

컴파일러가이 작업을 수행하는 이유는 아마도 효율성 때문이라고 생각합니다. TaskCompletionSource는 두 람다에서 사용되기 때문입니다. 그러나 이제는 이러한 람다 중 하나에 대한 참조가 여전히 참조되는 한 Request객체에 대한 참조 도 유지됩니다.

그래도이 문제를 피하는 방법을 알아내는 데는 아직 가깝지 않습니다.

편집 : 나는 그것을 쓸 때 분명히 이것을 생각하지 않았습니다. 다음과 같이 방법을 변경하여 문제를 해결했습니다.

    public Task<Response> TaskResponse
    {
        get
        {
            var tcs = new TaskCompletionSource<Response>();

            Timeout.Elapsed += (e, a) => tcs.SetException(new TimeoutException("Timeout at " + a.SignalTime));

            if (_response != null) tcs.SetResult(_response);
            else ResponseHandler += tcs.SetResult; //The event passes an object of type Response (derp) which is then assigned to the _response field.
            return tcs.Task;
        }
    }

_response클래스의 필드 인 것 같습니다 .

Referencing _response from the lambda will capture this in the closure, and will read this._response when the lambda executes.

To prevent this, you can copy _response to a local variable and use that instead. Note that that will cause it to use the current value of _response rather than its eventual value.

참고URL : https://stackoverflow.com/questions/12953907/resharper-implicitly-captured-closure-this

반응형