IT박스

.NET에 RAII가없는 이유는 무엇입니까?

itboxs 2020. 11. 22. 19:16
반응형

.NET에 RAII가없는 이유는 무엇입니까?


주로 C ++ 개발자이기 때문에 Java와 .NET RAII (Resource Acquisition Is Initialization)가 없다는 사실 은 항상 저를 괴롭 혔습니다. 정리의 부담이 클래스 작성자에서 소비자 ( try finally또는 .NET의 using구성을 통해 ) 로 이동한다는 사실은 현저히 열등한 것 같습니다.

Java에서는 모든 객체가 힙에 있고 가비지 수집기는 본질적으로 결정적 파괴를 지원하지 않기 때문에 RAII를 지원하지 않는 이유를 알지만 .NET에서는 value-types ( struct) 의 도입으로 (겉보기에) RAII의 완벽한 후보입니다. 스택에 생성 된 값 형식에는 잘 정의 된 범위가 있으며 C ++ 소멸자 의미 체계를 사용할 수 있습니다. 그러나 CLR은 값 형식이 소멸자를 갖는 것을 허용하지 않습니다.

내 무작위 검색에서 값 유형이 박스형 이면 가비지 수집기의 관할권에 속하므로 파괴가 결정적이지 않다는 주장이 하나 발견되었습니다 . 나는이 주장이 충분히 강하지 않다고 느낀다. RAII의 이점은 소멸자가있는 값 유형이 boxed (또는 클래스 구성원으로 사용) 될 수 없다고 말할만큼 충분히 크다고 생각합니다.

간단히 말해서 내 질문은 다음과 같습니다. RAII를 .NET에 도입하기 위해 값 유형을 사용할 수없는 다른 이유가 있습니까? (또는 RAII의 명백한 장점에 대한 나의 주장에 결함이 있다고 생각하십니까?)

편집 : 처음 4 개의 답변이 요점을 놓 쳤기 때문에 질문을 명확하게 표현하지 않았 음에 틀림 없습니다. 나는 알고 에 대해 Finalize그 비 결정적 특징은, 내가 알고 using구조와 나는이 두 가지 옵션이 RAII보다 열등하다고 생각. using클래스의 소비자가 기억해야 한 가지 더 (많은 사람들이 넣어 잊어 어떻게 StreamReaderA의 using블록?). 제 질문은 언어 디자인에 대한 철학적 질문입니다. 왜 그것이 현재의 방식이며 개선 될 수 있습니까?

예를 들어 일반적인 결정 론적으로 파괴 가능한 값 유형을 사용하면 usinglock키워드를 중복으로 만들 수 있습니다 (라이브러리 클래스에서 달성 가능).

    public struct Disposer<T> where T : IDisposable
    {
        T val;
        public Disposer(T t) { val = t; }
        public T Value { get { return val; } }
        ~Disposer()  // Currently illegal 
        {
            if (val != default(T))
                val.Dispose();
        }
    }

나는 내가 한때 보았지만 현재 그 기원을 찾을 수없는 적절한 인용문으로 끝낼 수는 없다.

내 차가운 죽은 손이 범위를 벗어나면 결정 론적 파괴를 취할 수 있습니다. - 아논


더 나은 제목은 "C # / VB에 RAII가없는 이유"입니다. C ++ / CLI (Managed C ++였던 낙태의 진화)에는 C ++와 똑같은 의미의 RAII가 있습니다. 나머지 CLI 언어가 사용하는 동일한 종료 패턴에 대한 구문 설탕 일뿐입니다 (C ++ / CLI 용 관리 객체의 소멸자는 사실상 종료 자입니다).

http://blogs.msdn.com/hsutter/archive/2004/07/31/203137.aspx를 좋아할 수 있습니다.


훌륭한 질문과 저를 크게 괴롭히는 질문입니다. RAII의 이점은 매우 다르게 인식되는 것으로 보입니다. .NET에 대한 경험상 결정 론적 (또는 최소한 신뢰할 수있는) 리소스 수집이 없다는 것이 주요 단점 중 하나입니다. 실제로 .NET은 명시 적 수집이 필요할 수 있지만 그렇지 않을 수도 있는 관리되지 않는 리소스를 처리하기 위해 전체 아키텍처를 여러 번 사용하도록 강요 했습니다. 물론 이는 전체 아키텍처를 더 어렵게 만들고 클라이언트의 관심을 더 중심적인 측면에서 멀어지게하기 때문에 큰 단점입니다.


Brian Harry는 여기 에 근거에 대한 좋은 게시물을 가지고 있습니다 .

다음은 발췌입니다.

결정 론적 마무리 및 값 유형 (구조체)은 어떻습니까?

-------------- 소멸자를 갖는 구조체에 대한 많은 질문을 보았습니다. 이것은 언급 할 가치가 있습니다. 일부 언어에없는 이유에는 다양한 문제가 있습니다.

(1) 구성-위에서 설명한 것과 같은 종류의 구성 이유 때문에 일반적인 경우에 결정 론적 수명을 제공하지 않습니다. 하나를 포함하는 비 결정적 클래스는 어쨌든 GC에 의해 종료 될 때까지 소멸자를 호출하지 않습니다.

(2) 복사 생성자-정말 좋은 곳은 스택 할당 로컬입니다. 그들은 방법으로 범위가 지정되고 모두 훌륭 할 것입니다. 안타깝게도 실제로 작동하려면 복사 생성자를 추가하고 인스턴스가 복사 될 때마다 호출해야합니다. 이것은 C ++에서 가장 추하고 가장 복잡한 것 중 하나입니다. 결국 예상하지 못한 곳에서 코드가 실행됩니다. 그것은 많은 언어 문제를 일으 킵니다. 일부 언어 디자이너는 이것을 멀리하기로 결정했습니다.

소멸자를 사용하여 구조체를 만들었지 만 위의 문제에 직면하여 동작을 합리적으로 만들기 위해 많은 제한을 추가했다고 가정 해 보겠습니다. 제한 사항은 다음과 같습니다.

(1) 지역 변수로만 선언 할 수 있습니다.

(2) 참조로만 전달할 수 있습니다.

(3) 할당 할 수 없으며 필드에 액세스하고 해당 필드에 대한 메서드를 호출 할 수만 있습니다.

(4) 상자에 넣을 수 없습니다.

(5) 일반적으로 복싱을 포함하기 때문에 Reflection (late binding)을 통해 사용하는 데 문제가 있습니다.

그 이상일 수도 있지만 좋은 시작입니다.

이것들은 무슨 소용이 있겠습니까? 실제로 로컬 변수로만 사용할 수있는 파일 또는 데이터베이스 연결 클래스를 생성 하시겠습니까? 나는 아무도 정말로 그렇게 할 것이라고 믿지 않는다. 대신 할 일은 범용 연결을 만든 다음 범위가 지정된 지역 변수로 사용할 자동 소멸 래퍼를 만드는 것입니다. 그런 다음 발신자는 사용하려는 것을 선택합니다. 호출자가 결정을 내 렸으며 개체 자체에 완전히 캡슐화되지 않았습니다. 몇 개의 섹션에 나오는 제안과 같은 것을 사용할 수 있다는 점을 감안할 때.

The replacement for RAII in .NET is the using-pattern, which works almost as well once you get used to it.


The closest you get to that is the very limited stackalloc operator.


There's some similar threads if you search for them but basicly what it boils down to is that if you want to RAII on .NET simply implement an IDisposable type and use the "using" statement to get deterministic Disposal. That way many of the same ideoms can be implemented and used in only a slightly more wordy manner.


IMHO, the big things that VB.net and C# need are:

  1. a "using" declaration for fields, which would cause the compiler to generate code to dispose of all fields thus tagged. The default behavior should be for the compiler to make a class implement IDisposable if it does not, or insert disposal logic before the start of the main disposal routine for any of a number of common IDisposal implementation patterns, or else use an attribute to specify that the disposal stuff should go in a routine with a particular name.
  2. a means of deterministically disposing of objects whose constructors and/or field initializers throw an exception, either by a default behavior (calling the default disposal method) or a custom behavior (calling a method with a particular name).
  3. For vb.net, an auto-generated method to null out all WithEvent fields.

All of those can be kludged pretty well in vb.net, and somewhat less well in C#, but first-class support for them would improve both languages.


You can do a form of RAII in .net and java using finalize() methods. A finalize() overload is called before the class is cleaned up by the GC and so can be used to clean up any resources that absolutely shouldn't be kept by the class (mutexes, sockets, file handles, etc). It still isn't deterministic though.

With .NET you can do some of this deterministically with the IDisposable interface and the using keyword, but this does have limitations (using construct when used required for deterministic behaviour, still no deterministic memory deallocation, not automatically used in classes, etc).

And yes, I feel there is a place for RAII ideas to be introduced into .NET and other managed languages, although the exact mechanism could be debated endlessly. The only other alternative I could see would be to introduce a GC that could handle arbitrary resource cleanup (not just memory) but then you have issues when said resources absolutely have to be released deterministically.

참고URL : https://stackoverflow.com/questions/173670/why-is-there-no-raii-in-net

반응형