닫고 처리-전화?


답변:


191

이 상황을 명확히하고 싶습니다.

Microsoft 지침에 따르면 Close적절한 방법 을 제공하는 것이 좋습니다 . 다음 은 프레임 워크 디자인 가이드 라인 에서 인용 한 내용입니다.

해당 지역의 표준 용어가 밀접한 경우 Close()에 추가하여 방법을 제공하십시오 Dispose(). 그렇게 할 때 Close구현을 동일하게 만드는 것이 중요합니다 Dispose...

대부분의 경우 Close와 Dispose방법은 동일합니다. 주요 차이점 사이 Close와 Dispose의 경우 SqlConnectionObject이다

응용 프로그램은 Close여러 번 호출 할 수 있습니다 . 예외는 생성되지 않습니다.

Dispose메소드 를 호출하면 SqlConnection객체 상태가 재설정됩니다. 폐기 된 SqlConnection 객체에서 메소드를 호출하려고하면 예외가 발생합니다.

그것은 말했다 :

  • 연결 개체를 한 번 사용하는 경우을 사용하십시오 Dispose.
  • 연결 개체를 재사용해야하는 경우 Close방법을 사용하십시오 .

5
Close ()에 대한 설명서 @Chris는 "연결 풀에 대한 연결을 해제하거나 연결 풀링이 비활성화 된 경우 연결을 닫습니다."라고 말합니다. 따라서 연결 풀이 넘치지 않도록 Close ()가 충분해야합니다.
— David Hammond

@DavidHammond : 네 말이 맞아. 이전 댓글을 삭제하고 있습니다.
— NotMe

3
.Dispose ()도 연결을 풀로 다시 해제합니까?
— oscilatingcretin

이것이 제가 10 년 만에 주제에 대해 읽은 최고의 주장입니다. 훌륭한 지적입니다.
— Michael Erickson

1
그래서 그것은 이렇게 작동합니다 1. con.Open() con.Close(); 2 con.Open(); // reuse 3. con.Dispose(); // use one time con.Open(); // error
— shaijut

24

평소와 같이 대답은 다음과 같습니다. 다른 수업 IDisposable은 다른 방식으로 구현 되며 필요한 연구를 수행하는 것은 당신에게 달려 있습니다.

가능한 SqlClient한 권장되는 방법은 다음을 수행하는 것입니다.

using (SqlConnection conn = /* Create new instance using your favorite method */)
{
    conn.Open();
    using (SqlCommand command = /* Create new instance using your favorite method */)
    {
        // Do work
    }
    conn.Close(); // Optional
}

당신은 해야 호출 할 Dispose(또는 Close연결에 *)! 마십시오 하지 가비지 수집기가 연결을 정리할 때까지 기다립니다,이 (적어도) 다음 GC주기까지 풀에서 연결을 묶어 것입니다. 호출하면 호출 할 Dispose필요가 없으며 Close, using구문을 Dispose올바르게 처리하기 쉽기 때문에 호출 할 이유가 없습니다 Close.

연결은 자동으로 풀링 되며 연결에서 Dispose/ Close를 호출 해도 물리적으로 연결이 닫히지 않습니다 (정상적인 상황에서). 자신의 풀링을 구현하지 마십시오. SqlClient풀에서 검색 될 때 연결에서 정리를 수행합니다 (예 : 데이터베이스 컨텍스트 및 연결 옵션 복원).

*를 호출 Close하는 경우 예외 안전 방식 (예 : catch 또는 finally 블록)으로 수행해야합니다.


"필요한 연구를하는 것은 당신에게 달려 있습니다"라고 말할 때, 그 연구는 무엇입니까? 내가 확실히 말하는 방법을 아는 유일한 방법은 리플렉션을 통하는 것이지만 대부분의 상황에서 "불법"이라는 단점이 있습니다.
— Storm

7
나는 말하지 않을 것입니다 : conn.Close(); // Optional선택 사항이 아닙니다. 중복적이고 불필요합니다. 객체를 두 번 배치하면 일부 코드 분석 도구에서 경고로 표시됩니다.
— Metalogic

@Metalogic 나는 적절한 사용법을 사용하여 Close를 호출하는 것이 불필요한 (그리고 추악한) 중복이라고 동의합니다. 그러나 nitpicking : Close 호출은 "처분" 이 아닙니다 (Dispose는 SqlConnection에 대해 Close를 의미 함). 에 비교하여 using (var x = ..) { x.Dispose(); }, 어떤 경우에는 x정말 "두 번 배치"입니다.
— user2864740

11

Dispose ()를 호출해야합니다!

Dispose ()는 개발자가 호출하고 가비지 콜렉터는 Finalize ()를 호출합니다. 객체에서 Dispose ()를 호출하지 않으면 사용 된 관리되지 않는 리소스는 가비지 수집기가 돌아와서 마무리 할 때까지 (그리고 누가 언제 일어날 지 알 때까지) 폐기되지 않습니다.

이 시나리오를 비 결정적 마무리라고하며 .net 개발자에게 일반적인 함정입니다. IDisposable을 구현하는 객체로 작업하는 경우 Dispose ()를 호출하십시오!

http://www.ondotnet.com/pub/a/oreilly/dotnet/news/programmingCsharp_0801.html?page=last

일부 개체에서 Disponse ()를 호출하고 연결에서 Close ()를 호출하거나 파일 핸들을 닫는 인스턴스가 많을 수도 있지만 (SqlConnection과 같이) Dispose ()를 호출하는 것이 가장 좋습니다. 가까운 시일 내에 객체를 재사용 할 계획이 아니라면.


26
이 의견은 완전히 거짓입니다. 가비지 수집기는 결코 호출하지 않습니다 Dispose.
— Stephen Cleary

3
추론 : 당신은 해야 호출 할 Dispose() 경우 사용하지 않는 using()것을 구현하는 클래스 IDisposable. 호출 된 클래스가 IDisposable을 구현하고 페이지 내 using()에서 사용법을 래핑 한 경우 Dispose()(pun 의도 한대로 촬영하십시오)로 처리 할 수 ​​있습니다 . 사용 Close()하지만, 명시 적으로 활용 아무것도 권장 Open()AFAIK.
— 르네 카 비스

다른 DBMS에 대해서는 잘 모르겠지만 PostgreSql 에서 두 가지를 모두 수행 할 수는 없습니다 . 일단 당신 Close의 연결은, 포스트 그레스가 자동으로 연결 식별자를 설정합니다 null. 거기서부터 Dispose이미 설정된 SQL 연결 식별자를 사용할 수 없습니다 null.
— ssd

10

를 들어 SqlConnection, 연결 자체의 관점에서, 그들은 동일합니다. Reflector에 따르면, Dispose()호출 Close()은 몇 가지 추가 메모리 프리 작업을 수행 할뿐 아니라 대부분 멤버를 null로 설정하여 호출합니다 .

Stream의 경우 실제로 동일합니다. Stream.Dispose()간단히 Close ()를 호출합니다.


1
확실합니까? MSDN 말한다 이 상속있어Component 하는 시도하고 호출 할 아무것도하지 않는 것Close() . 나는 그 알림의 어느 곳 DBConnection이나 SqlConnection그와 관련된 것을 볼 수 없습니다 . 그러나 DisposeMe()어디에도 참조되지 않는 개인 정보 가 있습니다 .
— Deanna

@Deanna 여기에서 재정의 됨 : github.com/dotnet/corefx/blob/…
— David Cumps

@DavidCumps 그 의견을 쓴지 4 년 만에 바뀌 었습니다. 내 링크가 더 이상 유효하지 않습니다.
— Deanna


6

이것은 빠른 조언이 긴 대답이되었습니다. 죄송합니다.

타일러가 그의 멋진 답변에서 지적했듯이 호출 Dispose()은 훌륭한 프로그래밍 관행입니다. 이 방법은 필요한 모든 자원 확보를 "집결"하여 불필요한 공개 자원이 없기 때문입니다. 예를 들어, 파일에 텍스트를 쓰고 파일을 닫지 못한 경우 (자원을 비우는 경우) 해당 파일은 열린 상태로 유지되며 GC가 돌아와서 필요한 것을 수행 할 때까지 다른 사람이 파일에 쓸 수 없습니다. 끝난.

이제 어떤 경우에는을 ( StreamWriter.Close()를) 재정의하는 것과 같이 처리하는 클래스에 대해 더 구체적인 "완료"메서드 가 있습니다 TextWriter.Close(). 실제로 이들은 일반적으로 상황에 더 적합합니다. Close()예를 들어 StreamWriter 's Dispose()는 객체를 보내기 전에 스트림과 기본 인코더를 플러시 합니다! 멋있는!

그러나 MSDN을 살펴보면 Microsoft조차도 수많은 클로저 및 디스 포저로 인해 혼란 스러울 수 있습니다. 예를 들어, 이 웹 페이지 에서 일부 예 Close()에서 암시 적 전에 호출됩니다 Dispose()( 암시 적 이유를 이해하지 못하는 경우 문 사용 참조 ). 특히 웹 페이지에서는 신경 쓰지 않습니다. 왜 그런가요? 나도 당황했다.

내가 생각한 이유는 (이것은 독창적 인 연구 이며 내가 틀렸다면 분명히 명성을 잃을 수 있음을 강조합니다) Close()자원이 열려있는 동안 예외가 발생하는 동시에 실패 Dispose()할 수 있기 때문 입니다. 어떤 이유 A는 Dispose()항상 보호해야 Close()호출 (말장난에 대한 유감을).

MyResource r = new MyResource();

try {
  r.Write(new Whatever());

  r.Close()
finally {
  r.Dispose();
}

그리고 네, 마이크로 소프트가 그 한 가지 예에 착수했다고 생각합니다. 아마도 타임 스탬프가 파일로 플러시되지 않을 것입니다.

내일 이전 코드를 수정하고 있습니다.

편집 : 죄송합니다 브래넌, 나는 당신의 대답에 대해 언급 할 수는 없지만 확신이 호출에 좋은 아이디어이다 있습니다 Close()A의 finally블록? 그것의 예외는 블록의 나머지 부분을 망칠 수 있다고 생각합니다.

Brannon 's에 대한 답변 : 훌륭합니다. Close()실제로 필요할 때 호출하는 것을 잊지 마십시오 (예 : 스트림을 다룰 때-.NET의 SQL 연결에 대해 잘 모름).


실제로 Close ()를 호출하지 않고 Dispose () 및 'using'구문 이 올바른 작업을 수행하도록합니다 . Dispose를 호출하지 않는 경우 예외 안전 방식으로 Close를 호출해야합니다. finally 블록에 예외 처리를 추가하는 것이 좋습니다.
— Brannon

내 의견은 SqlClient에 대한 것입니다. 요점은 사용중인 클래스를 이해해야한다는 것입니다. 항상 Dispose를 호출한다고해서 반드시 정답은 아닙니다.
— Brannon

2

iDisposable로 타입 캐스트하고 dispose를 호출하십시오. 함수의 이름에 관계없이 "iDisposable.Dispose"를 구현하도록 구성된 모든 메소드를 호출합니다.


"함수 이름" "Dispose": 따라서 우리는 초기 질문으로 돌아갑니다 :}
— user2864740

이 함수는에 바인딩되어 IDisposable.Dispose있지만 이것이 이름 인 것은 아닙니다. vb.net에서는 함수와 관련이없는 이름을 가진 여러 인터페이스 멤버에 함수를 바인딩 할 수 있습니다.
— supercat

다음과 같이 캐스트하십시오 :using (myObj as IDisposable)
— Yousha Aleayoub

2

일반적으로 Close (), Abort () 및 Dispose ()에서 문제가 발생하지만 차이점을 알려 드리겠습니다.

1) ABORT :-중단을 호출하면 클라이언트가 서버에 알리지 않고 연결을 삭제하므로 서버가 일정 시간 (약 1 분) 동안 기다릴 수 있으므로 사용하지 않는 것이 좋습니다. 대량 요청이있는 경우 제한된 연결 풀에 시간 초과가 발생할 수 있으므로 abort ()를 사용할 수 없습니다.

2) 닫기 :-닫기는 연결을 닫을 때 서버를 호출하고 서버가 그 쪽에서 닫는 것을 승인하기 때문에 연결을 닫는 매우 좋은 방법입니다.

여기에 한 가지 더 있습니다. 어떤 경우에는 오류가 발생하면 해당 Connection.close ()에 코드를 작성하는 것이 좋은 방법이 아닙니다. 그 당시 통신 상태에 오류가 있기 때문입니다.

3) 처리 :-폐쇄 유형 중 하나이지만 연결을 닫은 후에는 다시 열 수 없습니다.

이 방법으로 시도하십시오.

private void CloseConnection(Client client)
    {
        if (client != null && client.State == CommunicationState.Opened)
        {
            client.Close();
        }
        else
        {
            client.Abort();
        }
    }

client != null모든 사용을 보호하지는 않기 때문에 체크인 이 잘못되었거나 오해의 소지가 있습니다. 또한 코드가 "이 연결이 열리지 않고 닫혀 있어야합니다"상태가되는 방법을 잘 모르겠습니다.
— user2864740
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.