예외 안전을 위해 "범위 지정 동작"을 얻기위한 수단으로 IDisposable 및 "사용"을 사용하는 것이 악의적입니까?


112

내가 C ++에서 자주 사용했던 것은 생성자와 소멸자 를 통해 A클래스가 다른 클래스에 대한 상태 진입 및 종료 조건을 처리 하도록하여 해당 범위의 무언가가 예외를 던지면 B가 알려진 상태를 가질 수 있도록하는 것입니다. 범위가 종료되었습니다. 이것은 약어가가는 한 순수한 RAII는 아니지만 그럼에도 불구하고 확립 된 패턴입니다.BA

C #에서는 종종

class FrobbleManager
{
    ...

    private void FiddleTheFrobble()
    {
        this.Frobble.Unlock();
        Foo();                  // Can throw
        this.Frobble.Fiddle();  // Can throw
        Bar();                  // Can throw
        this.Frobble.Lock();
    }
}

이렇게해야하는

private void FiddleTheFrobble()
{
    this.Frobble.Unlock();

    try
    {            
        Foo();                  // Can throw
        this.Frobble.Fiddle();  // Can throw
        Bar();                  // Can throw
    }
    finally
    {
        this.Frobble.Lock();
    }
}

반품 Frobble시 상태 를 보증하고 싶다면 FiddleTheFrobble. 코드는 더 좋을 것입니다.

private void FiddleTheFrobble()
{
    using (var janitor = new FrobbleJanitor(this.Frobble))
    {            
        Foo();                  // Can throw
        this.Frobble.Fiddle();  // Can throw
        Bar();                  // Can throw
    }
}

여기서 FrobbleJanitor보이는 대략 좋아

class FrobbleJanitor : IDisposable
{
    private Frobble frobble;

    public FrobbleJanitor(Frobble frobble)
    {
        this.frobble = frobble;
        this.frobble.Unlock();
    }

    public void Dispose()
    {
        this.frobble.Lock();
    }
}

그리고 그것이 제가하고 싶은 방법입니다. 내가 무엇 때문에 지금 현실은, 잡는다 원하는 사용하는 것은 필요로 그를FrobbleJanitor 사용 하여 using . 나는 이것을 코드 검토 문제라고 생각할 수 있지만 무언가가 나를 괴롭힌다.

질문 : 위의 내용이 using및의 남용으로 간주 IDisposable됩니까?


23
클래스 및 메서드 이름 만 +1합니다. :-). 음, 공정, 할 수 실제 질문입니다.
Joey

2
@Johannes : 네, 그 이유를 알 수 있습니다. 대부분의 사람들은 바이올린을 휘두르는 것뿐입니다. ;-) 그건 그렇고, 이름 유사성에 +1.
Johann Gerell 2010 년

아마도 lock (this) {..} 범위를 사용하여이 예제에서 동일한 결과를 얻을 수 있습니까?
oɔɯǝɹ 2010-01-20

1
@ oɔɯǝɹ : lock ()을 사용하여 다른 스레드의 항목에 동시에 액세스하는 것을 방지합니다. 내가 설명하는 시나리오와 관련이 없습니다.
Johann Gerell

1
다음 버전의 C #에서 종료자가없는 IScopeable :)
Jon Raynor

답변:


33

필연적으로 그렇게 생각하지는 않습니다. 기술적으로 식별 가능 되어 관리되지 않는 자원을 가지고 일에 사용되는 의미,하지만 그때 사용하는 지시어의 일반적인 패턴을 구현 단지 깔끔한 방법입니다try .. finally { dispose } .

순수 주의자는 '그렇다-그것은 학대 적이다'라고 주장 할 것이고, 순수 주의적 의미에서는 그렇다. 그러나 우리 대부분은 순수주의적인 관점에서 코딩하는 것이 아니라 반 예술적인 관점에서 코딩합니다. 이런 식으로 '사용'구조를 사용하는 것은 제 생각에 실제로 꽤 예술적입니다.

IDisposable 위에 다른 인터페이스를 붙여서 조금 더 멀리 밀어 넣어야합니다.이 인터페이스가 IDisposable을 의미하는 이유를 다른 개발자에게 설명해야합니다.

이 작업에 대한 다른 많은 대안이 있지만 궁극적으로 이것만큼 깔끔 할 것이라고 생각할 수 없으므로 시도하십시오!


2
나는 그것이 또한 "사용"의 예술적 사용이라고 믿습니다. Eric Gunnerson의 의견에 링크 된 Samual Jack의 게시물이 이러한 "사용"구현을 검증한다고 생각합니다. 나는 이것에 대해 Andras와 Eric이 만든 훌륭한 포인트를 볼 수 있습니다.
IAbstract 2010

1
나는 Eric Gunnerson에게 얼마 전에 이것에 대해 이야기했고 그에 따르면 C # 디자인 팀의 의도는 using이 범위를 나타냅니다. 실제로 그는 lock 문 이전에 사용하여 설계했다면 lock 문이 없을 수도 있다고 가정했습니다. 모니터 호출 등의 사용 블록이었을 것입니다. 업데이트 : 다음 답변은 언어 팀에있는 Eric Lippert입니다. ;) 아마도 C # 팀 자체가 이것에 대해 완전히 동의하지 않았습니까? Gunnerson과의 토론의 맥락은 TimedLock 클래스였습니다 : bit.ly/lKugIO
Haacked

2
@Haacked-재미 있지 않나요? 귀하의 의견은 내 요점을 완전히 증명합니다. 당신이 팀의 한 사람과 이야기를했고 그 사람이 전부 였다고; 그런 다음 같은 팀의 Eric Lippert가 동의하지 않습니다. 내 관점에서; C #은 인터페이스를 악용하는 키워드를 제공하며 여러 시나리오에서 작동하는 멋진 코드 패턴을 생성합니다. 우리가 그것을 남용해서는 안된다면 C #은 그것을 강제 할 다른 방법을 찾아야합니다. 어느 쪽이든, 디자이너는 아마도 여기에서 오리를 연속으로 가져와야 할 것입니다! 그동안 : using(Html.BeginForm())선생님? 내가 괜찮아도 상관 없어! :)
Andras Zoltan

71

나는 이것이 using 문장의 남용이라고 생각합니다. 나는이 위치에서 내가 소수라는 것을 알고 있습니다.

나는 이것이 세 가지 이유로 남용이라고 생각합니다.

내가 기대하고 있기 때문에 먼저, 그하는 데 사용됩니다 "사용" 자원 사용 하고 당신이 그것을 완료하면 폐기를 . 프로그램 상태 변경 은 리소스를 사용 하지 않으며 다시 변경해도 폐기 되지 않습니다. 도 아무것도 . 따라서 상태를 변경하고 복원하기 위해 "사용"하는 것은 남용입니다. 코드는 일반 독자에게 오해의 소지가 있습니다.

둘째, "사용"은 필수가 아닌 예의 로 사용되기를 기대하기 때문 입니다. 이 때문에 당신이 그것을 완료하면 당신이 파일 처분 "을 사용하여"사용하는 이유는 아닙니다 필요 그렇게하지만 때문에 정중 - 다른 사람이 그래서 "완료를 말하고, 그 파일을 사용하여 대기 중일 수 있습니다 지금 "은 도덕적으로 올바른 일입니다. 나는 "사용"을 리팩토링하여 사용 된 리소스를 더 오래 보관하고 나중에 폐기 할 수 있어야하며 그렇게함으로써 다른 프로세스약간의 불편을 끼치게 . 프로그램 상태에 의미 론적 영향을 미치는 "사용"블록 그것은 필요가 아닌 편의성과 공손함을 위해 존재하는 것처럼 보이는 구조에서 프로그램 상태의 중요하고 필요한 변이를 숨기기 때문에 학대 적입니다.

셋째, 프로그램의 동작은 상태에 따라 결정됩니다. 주의 깊은 상태 조작의 필요성이 바로 우리가 처음에이 대화를하는 이유입니다. 원래 프로그램을 분석하는 방법을 고려해 보겠습니다.

이것을 제 사무실의 코드 리뷰에 가져 오 셨나요? 제가 물어볼 첫 번째 질문은 "예외가 발생하면 프 러블을 잠그는 것이 정말 맞습니까?"입니다. 이 일이 무슨 일이 일어나더라도 공격적으로 프 러블을 다시 잠그는 것이 프로그램에서 뻔뻔스럽게 분명합니다. 맞습니까? 예외가 발생했습니다. 프로그램이 알 수없는 상태입니다. 우리는 Foo, Fiddle 또는 Bar가 던 졌는지, 왜 던 졌는지 또는 정리되지 않은 다른 상태에 어떤 돌연변이를 수행했는지 알 수 없습니다. 그 끔찍한 상황 에서 다시 잠그는 것이 항상 옳은 일이라고 저 를 설득 할 수 있습니까 ?

그럴 수도 있고 아닐 수도 있습니다. 내 요점은 원래 작성된 코드로 코드를 사용하여 코드 검토자가 질문하는 것을 알고 있다는 것 입니다. "사용"을 사용하는 코드에서는 질문을해야할지 모르겠습니다. 나는 "using"블록이 리소스를 할당하고 약간 사용하고 완료되면 정중하게 처리한다고 가정합니다. "using"블록의 닫는 중괄호임의로 많은 경우 예외적으로 내 프로그램 상태를 변경 하는 것이 아닙니다. 프로그램 상태 일관성 조건을 위반했습니다.

의미 론적 효과를 갖기 위해 "using"블록을 사용하면이 프로그램이 조각화됩니다.

}

매우 의미가 있습니다. 제가 그 하나의 폐쇄 보조기를 볼 때 "저 보조기가 내 프로그램의 글로벌 상태에 광범위한 영향을 미치는 부작용이 있습니다"라고 즉시 생각하지 않습니다. 하지만 이렇게 "사용"을 남용하면 갑자기 그렇게됩니다.

두 번째로 원래 코드를 보았는지 물어볼 것입니다. "잠금 해제 후 시도가 입력되기 전에 예외가 발생하면 어떻게됩니까?" 최적화되지 않은 어셈블리를 실행하는 경우 컴파일러가 시도 전에 no-op 명령을 삽입했을 수 있으며 no-op에서 스레드 중단 예외가 발생할 수 있습니다. 이것은 드물지만 실제로는 특히 웹 서버에서 발생합니다. 이 경우 잠금 해제가 발생하지만 시도 전에 예외가 발생했기 때문에 잠금이 발생하지 않습니다. 이 코드가이 문제에 취약 할 수 있으며 실제로 작성해야합니다.

bool needsLock = false;
try
{
    // must be carefully written so that needsLock is set
    // if and only if the unlock happened:

    this.Frobble.AtomicUnlock(ref needsLock);
    blah blah blah
}
finally
{
    if (needsLock) this.Frobble.Lock();
}

다시 말하지만, 아마도 그렇지 않을 수도 있지만 질문을해야한다는 것을 알고 있습니다. "using"버전에서는 동일한 문제에 취약합니다. Frobble이 잠긴 후 사용과 관련된 try-protected 영역이 입력되기 전에 스레드 중단 예외가 발생할 수 있습니다. 그러나 "사용"버전에서는 이것이 "그래서 무엇입니까?"라고 가정합니다. 상태. 그런 일이 발생하면 안타까운 일이지만 "사용"은 매우 중요한 프로그램 상태를 변경하는 것이 아니라 예의를 갖추기위한 것이라고 생각합니다. 끔찍한 스레드 중단 예외가 정확히 잘못된 시간에 발생하면 가비지 수집기가 종료자를 실행하여 결국 해당 리소스를 정리할 것이라고 가정합니다.


18
나는 질문에 다르게 대답 할 것이지만 그것은 논쟁의 여지가있는 글이라고 생각합니다. 그러나 나는 using정확성 문제 라기보다는 공손함이라는 당신의 주장을 쟁취합니다. 리소스 누수는 정확성 문제라고 생각하지만, 종종 중요도가 높은 버그가 아닐 정도로 사소합니다. 따라서 using블록은 이미 프로그램 상태에 의미 론적 영향을 미치며 , 블록 방지하는 것은 다른 프로세스에 대한 "불편 ​​함"이 아니라 잠재적으로 손상된 환경입니다. 질문이 암시하는 다른 유형의 의미 론적 영향도 적절하다는 것은 아닙니다.
kvb

13
리소스 누출은 정확성 문제입니다. 그러나 "사용"을 사용하지 않는다고해서 자원이 유출되는 것은 아닙니다. 종료자가 실행되면 리소스가 결국 정리됩니다. 정리는 원하는만큼 공격적이고시기 적절하지 않을 수 있지만 일어날 것입니다.
Eric Lippert

7
멋진 게시물, 여기 내 두 센트가 있습니다. :) usingC #에서 가난한 사람의 측면 지향 위버이기 때문에 많은 "남용"이 의심 됩니다. 개발자가 정말로 원하는 것은 코드를 복제하지 않고도 블록의 끝에서 일부 공통 코드가 실행되도록 보장하는 방법입니다. C #은 현재 AOP를 지원하지 않습니다 (MarshalByRefObject 및 PostSharp는 견딜 수 없음). 그러나 컴파일러에서 using 문을 변환하면 결정적 자원 처리의 의미를 다시 사용하여 간단한 AOP를 달성 할 수 있습니다. 안 좋은 연습 있지만, 그것은 ..... 위로 통과 때로는 매력적
LBushkin

11
나는 일반적으로 귀하의 입장에 동의하지만 용도 변경의 이점 using이 너무 매력적이어서 포기할 수없는 경우가 있습니다. 제가 생각할 수있는 가장 좋은 예는 코드 타이밍을 추적하고보고하는 것입니다. using( TimingTrace.Start("MyMethod") ) { /* code */ } 다시 말하지만 이것은 AOP입니다 Start(). 블록이 시작되기 전에 시작 시간을 Dispose()캡처하고 종료 시간을 캡처하고 활동을 기록합니다. 프로그램 상태를 변경하지 않으며 예외에 구애받지 않습니다. 그것은 또한 꽤 많은 배관을 피하고 패턴으로 자주 사용되어 혼란스러운 의미를 완화하기 때문에 매력적입니다.
LBushkin

6
재미있게도 저는 항상 사용을 RAII를 지원하는 수단으로 생각했습니다. 잠금을 자원의 한 유형으로 간주하는 것이 나에게 상당히 직관적 인 것 같습니다.
Brian

27

깨끗하고 범위가 지정된 코드를 원한다면 람다를 사용할 수도 있습니다.

myFribble.SafeExecute(() =>
    {
        myFribble.DangerDanger();
        myFribble.LiveOnTheEdge();
    });

를 Where .SafeExecute(Action fribbleAction)방법은 랩 try- catch- finally블록.


이 예에서는 진입 상태를 놓쳤습니다. . 또한, 반드시 그렇게 람다 뭔가 당신이에있어 어떤 상태 아무 생각이 없다가 발생하는 경우, 마침내 시도 / 마지막으로,하지만 당신은 호출하지 않는 것을 포장
요한 게렐

1
아! 좋아, 난 당신이 그 의미 추측 SafeExecuteA는 Fribble어떤 호출 방법 Unlock()Lock()마지막으로 감싸 시도 / 인치 그럼 사과드립니다. 나는 즉시 SafeExecute일반적인 확장 방법으로 보았 으므로 진입 및 종료 상태가 없음을 언급했습니다. 내 잘못이야.
Johann Gerell 2010 년

1
이 접근에 대해 매우 조심하십시오. 체포 된 지역 주민들의 경우 의도하지 않은 위험한 미묘한 수명 연장이있을 수 있습니다!
jason

4
수다. try / catch / finally를 숨기는 이유는 무엇입니까? 다른 사람이 읽을 수 있도록 코드를 숨 깁니다.
Frank Schwieterman 2010 년

2
@Yukky Frank : 아무것도 "숨기기" 는 생각이 아니라 질문자의 요청이었습니다. :-P ... 즉, 요청은 마침내 "자신을 반복하지 마십시오"의 문제입니다. 무언가를 명확하게 획득 / 해제하는 동일한 상용구 "프레임"을 필요로하는 많은 메소드가있을 수 있으며이를 호출자에게 부과하지 않으려 고합니다 (캡슐화를 생각하십시오). 또한 .SafeExecute (...)와 같은 메서드의 이름을 더 명확하게 지정하여 그들이하는 일을 충분히 잘 전달할 수 있습니다.
herzmeister

25

는 C # 언어 디자인 팀에 있던 에릭 Gunnerson은 준 이 답변을 꽤 많이 같은 질문에 :

Doug가 묻습니다.

re : 제한 시간이있는 잠금 문 ...

여러 방법에서 일반적인 패턴 을 다루기 위해 이전에이 트릭을 수행했습니다 . 일반적으로 잠금 획득 이지만 다른 일부가 있습니다 . 문제는 객체가 " 범위가 끝날 때까지 콜백 "만큼 일회용이 아니기 때문에 항상 해킹처럼 느껴진다는 것 입니다.

더그,

using 문을 결정했을 때 정확히이 시나리오에 사용할 수 있도록 개체를 처리하는 것보다 "사용"이라는 이름을 지정하기로 결정했습니다.


4
그가 "정확히이 시나리오"라고 말했을 때 그 인용문은 그가이 미래의 질문을 언급하고 있었는지 의심 스럽기 때문에 그가 언급 한 것을 말해야합니다.
Frank Schwieterman 2010 년

4
@Frank Schwieterman : 견적을 완료했습니다. 분명히, C #을 팀의 사람들은 씽크 using기능이되었다 되지 자원의 처분 제한 될 수 있습니다.
paercebal 2010

11

미끄러운 경사입니다. IDisposable에는 종료자가 백업 한 계약이 있습니다. 귀하의 경우 종료자는 쓸모가 없습니다. 클라이언트에게 using 문을 사용하도록 강요 할 수 없으며 사용하도록 권장 할뿐입니다. 다음과 같은 방법으로 강제 할 수 있습니다.

void UseMeUnlocked(Action callback) {
  Unlock();
  try {
    callback();
  }
  finally {
    Lock();
  }
}

그러나 그것은 람다 없이는 조금 어색 해지는 경향이 있습니다. 즉, 나는 당신처럼 IDisposable을 사용했습니다.

그러나 귀하의 게시물에는 이것을 안티 패턴에 위험하게 가깝게 만드는 세부 사항이 있습니다. 이러한 메서드가 예외를 throw 할 수 있다고 언급했습니다. 이것은 호출자가 무시할 수있는 것이 아닙니다. 그는 그것에 대해 세 가지를 할 수 있습니다.

  • 아무것도하지 마십시오. 예외는 복구 할 수 없습니다. 정상적인 경우입니다. Unlock 호출은 중요하지 않습니다.
  • 예외 포착 및 처리
  • 그의 코드에서 상태를 복원하고 예외가 호출 체인을 통과하도록합니다.

후자의 두 가지는 호출자가 명시 적으로 try 블록을 작성해야합니다. 이제 using 문이 방해가됩니다. 그것은 당신의 수업이 상태를 관리하고 있으며 추가 작업을 할 필요가 없다고 믿게 만드는 혼수 상태에 빠지게 할 수 있습니다. 거의 정확하지 않습니다.


강제 사건은 위의 "herzmeister der welten"에 의해 주어 졌다고 생각합니다. OP가 예를 좋아하지 않는 것 같더라도 말입니다.
Benjamin Podszun 2010 년

예, 저는 그의 SafeExecute일반적인 확장 방법으로 해석했습니다 . 나는 그것이 가능성으로 의미하는 것을 지금 볼 Fribble호출 방법 Unlock()Lock()마지막으로 감싸 시도 /에. 내 잘못이야.
Johann Gerell 2010 년

예외를 무시한다고해서 복구 할 수 없다는 의미는 아닙니다. 이는 스택에서 위에서 처리된다는 것을 의미합니다. 예를 들어 예외를 사용하여 스레드를 정상적으로 종료 할 수 있습니다. 이 경우 잠긴 잠금을 포함하여 리소스를 올바르게 해제해야합니다.
paercebal 2010-08-27

7

실제 사례는 ASP.net MVC의 BeginForm입니다. 기본적으로 다음과 같이 작성할 수 있습니다.

Html.BeginForm(...);
Html.TextBox(...);
Html.EndForm();

또는

using(Html.BeginForm(...)){
    Html.TextBox(...);
}

Html.EndForm은 Dispose를 호출하고 Dispose는 </form>태그 만 출력합니다 . 이것에 대한 좋은 점은 {} 괄호가 가시적 인 "범위"를 생성하여 양식 내에 무엇이 있는지, 무엇이 아닌지 쉽게 볼 수 있다는 것입니다.

나는 그것을 과도하게 사용하지 않을 것이다. 그러나 본질적으로 IDisposable은 단지 "당신이 그것을 끝냈을 때이 함수를 호출해야한다"라고 말하는 방법 일 뿐이다. MvcForm은이를 사용하여 폼이 닫혔는지 확인하고 Stream은이를 사용하여 스트림이 닫혔는지 확인하고 개체가 잠금 해제되었는지 확인하는 데 사용할 수 있습니다.

개인적으로 다음 두 가지 규칙이 참인 경우에만 사용하지만 임의로 설정합니다.

  • Dispose는 항상 실행해야하는 함수 여야하므로 Null-Check를 제외하고 조건이 없어야합니다.
  • Dispose () 후에는 개체를 다시 사용할 수 없어야합니다. 재사용 가능한 객체를 원한다면 폐기하는 대신 열기 / 닫기 메소드를 제공하고 싶습니다. 그래서 폐기 된 객체를 사용하려고 할 때 InvalidOperationException을 던졌습니다.

결국, 그것은 모두 기대에 관한 것입니다. 개체가 IDisposable을 구현하면 정리가 필요하다고 가정하므로이를 호출합니다. 보통 "종료"기능이있는 것보다 낫다고 생각합니다.

즉,이 라인이 마음에 들지 않습니다.

this.Frobble.Fiddle();

FrobbleJanitor가 이제 Frobble을 "소유"하고 있으므로, 대신 Janitor에서 Frobble에게 Fiddle을 호출하는 것이 낫지 않을까요?


"나는이 줄이 마음에 들지 않는다"에 대해-질문을 공식화 할 때 실제로 그렇게하는 것을 잠시 생각했지만 내 질문의 의미를 어지럽히고 싶지 않았습니다. 하지만 나는 당신에게 동의합니다. 거의. :)
Johann Gerell 2010 년

1
Microsoft 자체의 예를 제공하기 위해 찬성했습니다. 언급 한 경우에 throw 될 특정 예외가 있습니다. ObjectDisposedException.
Antitoon

4

우리는 코드베이스에서이 패턴을 많이 사용하고 있으며 이전에 모든 곳에서 본 적이 있습니다. 여기서도 논의되었을 것입니다. 일반적으로이 작업을 수행하는 데 어떤 문제가 있는지 알 수 없으며 유용한 패턴을 제공하며 실제 피해를주지 않습니다.


4

이것에 착수하십시오 : 나는 이것이 깨지기 쉽지만 유용하다는 것에 대부분 동의합니다. System.Transaction.TransactionScope를 알려 드리고자합니다.원하는대로 수행 클래스 .

일반적으로 나는 구문을 좋아하며 실제 고기에서 많은 혼란을 제거합니다. 위의 예와 같이 도우미 클래스에 좋은 이름을 지정하는 것을 고려하십시오. 이름은 코드 조각을 캡슐화한다는 것을 알려야합니다. * 스코프, * 블록 또는 이와 유사한 것이이를 수행해야합니다.


1
"Janitor"는 ScopeGuard가 Loki로 이동하기 전에도 스코프 가드에 대한 Andrei Alexandrescu의 오래된 C ++ 기사에서 나왔습니다.
Johann Gerell 2010 년

@Benjamin : 저는 TransactionScope 클래스를 좋아하는데, 전에 들어 본 적이 없습니다. 나는 그것이 포함되지 닷넷 CF의 땅에있어 어쩌면 때문에 ... :-(
요한 게렐

4

참고 : 내 관점은 아마도 내 C ++ 배경에서 편향된 것이므로 내 대답의 값은 가능한 편향에 대해 평가되어야합니다.

C # 언어 사양은 무엇입니까?

C # 언어 사양 인용 :

8.13 using 문

[...]

자원 클래스 또는 구조체를 처분라는 하나의 매개 변수가 구현 방법을 포함한다 System.IDisposable 즉. 리소스를 사용하는 코드는 Dispose를 호출하여 리소스가 더 이상 필요하지 않음을 나타낼 수 있습니다. Dispose가 호출되지 않으면 가비지 수집의 결과로 자동 삭제가 발생합니다.

자원을 사용하는 코드는 물론, 코드에 의해 시작 using키워드와 연결된 범위까지 가고 using.

잠금이 리소스이기 때문에 이것이 괜찮다고 생각합니다.

키워드 using가 잘못 선택되었을 수 있습니다. 아마도 scoped.

그러면 거의 모든 것을 자원으로 간주 할 수 있습니다. 파일 핸들. 네트워크 연결 ... 스레드?

스레드 ???

사용 (또는 남용) using키워드를 합니까?

범위를 종료하기 전에 스레드의 작업이 종료되었는지 확인하기 위해 키워드 를 (남용) 사용하는 것이 반짝using 일까요?

Herb Sutter가 반짝 거리는 것 같아요 그는 끝까지 스레드의 작업을 위해 대기 할 IDispose 패턴의 재미있는 사용을 제공합니다 같이 :

http://www.drdobbs.com/go-parallel/article/showArticle.jhtml?articleID=225700095

다음은 기사에서 복사하여 붙여 넣은 코드입니다.

// C# example
using( Active a = new Active() ) {    // creates private thread
       
       a.SomeWork();                  // enqueues work
       
       a.MoreWork();                   // enqueues work
       
} // waits for work to complete and joins with private thread

Active 개체에 대한 C # 코드는 제공되지 않지만 C #은 소멸자에 포함 된 C ++ 버전의 코드에 대해 IDispose 패턴을 사용합니다. 그리고 C ++ 버전을 살펴보면이 기사의 다른 발췌 본에서 볼 수 있듯이 종료하기 전에 내부 스레드가 끝날 때까지 기다리는 소멸자를 볼 수 있습니다.

~Active() {
    // etc.
    thd->join();
 }

그래서 Herb에 관한 한, 그것은 반짝 입니다.


3

귀하의 질문에 대한 대답은 '아니요'라고 생각합니다 IDisposable. 이것은를 남용하지 않을 것입니다 .

IDisposable인터페이스를 이해하는 방법 은 일단 삭제 된 객체로 작업해서는 안된다는 것입니다 ( Dispose원하는만큼 자주 메서드 를 호출 할 수 있다는 점을 제외 하면).

명령문에 도달 할 때마다 명시 적으로 새로 작성하므로 동일한 객체를 두 번 사용하지 않습니다 . 목적이 다른 개체를 관리 하는 것이므로이 ( "관리되는") 리소스를 해제하는 작업에 적절 해 보입니다.FrobbleJanitorusingFrobbeJanitorDispose

(Btw.의 적절한 구현을 보여주는 표준 샘플 코드는 Dispose파일 시스템 핸들과 같은 관리되지 않는 리소스뿐만 아니라 관리되는 리소스도 해제되어야 함을 거의 항상 제안합니다.)

내가 개인적으로 걱정하는 유일한 점 은 & 연산이 직접 표시 using (var janitor = new FrobbleJanitor())되는보다 명확한 try..finally블록 보다 무슨 일이 일어나고 있는지 명확하지 않다는 것 입니다. 그러나 어떤 접근 방식을 취하는지는 아마도 개인적인 취향에 달려 있습니다.LockUnlock


1

학대하지 않습니다. 당신은 그들이 만들어진 것을 사용하고 있습니다. 그러나 필요에 따라 서로를 고려해야 할 수도 있습니다. 예를 들어 '예술성'을 선택한 경우 '사용'을 사용할 수 있지만 코드 조각이 많이 실행되면 성능상의 이유로 'try'.. 'finally'구문을 사용할 수 있습니다. '사용'은 일반적으로 객체의 생성을 포함하기 때문입니다.


1

당신이 옳은 일을했다고 생각합니다. Dispose () 오버로딩은 나중에 동일한 클래스에서 실제로 수행해야하는 정리 작업에 문제가 될 수 있으며 해당 정리의 수명이 잠금을 유지하려는 시간과 다르게 변경되었습니다. 그러나 Frobble 잠금 및 잠금 해제만을 담당하는 별도의 클래스 (FrobbleJanitor)를 만들었으므로 문제가 발생하지 않을만큼 충분히 분리되어 있습니다.

하지만 FrobbleJanitor의 이름을 FrobbleLockSession과 같은 이름으로 변경하겠습니다.


이름 변경에 대해-Lock / Unlock을 다루는 주된 이유 중 "Janitor"를 사용했습니다. 나는 그것이 다른 이름 선택과 운이 좋다고 생각했습니다. ;-) 만약 내가이 방법을 내 코드베이스 전체에서 패턴으로 사용한다면, "세션"에서 암시 한 것처럼 좀 더 일반적으로 설명하는 것을 확실히 포함시킬 것입니다. 이것이 이전 C ++ 시절 이었다면 아마도 FrobbleUnlockScope를 사용했을 것입니다.
Johann Gerell 2010 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.