Share via


Avoiding Problems with the Using Statement

이 샘플에서는 형식화된 클라이언트를 사용할 때 C# "using" 문을 사용하여 리소스를 자동으로 정리하지 않아야 한다는 것을 보여 줍니다. 이 샘플은 계산기 서비스를 구현하는 Getting Started 샘플을 기반으로 합니다. 이 샘플에서 클라이언트는 콘솔 응용 프로그램(.exe)이고 서비스는 IIS(인터넷 정보 서비스)를 통해 호스팅됩니다.

참고

이 샘플의 설치 절차 및 빌드 지침은 이 항목의 끝부분에 나와 있습니다.

이 샘플에서는 형식화된 클라이언트와 함께 C# "using" 문을 사용할 경우 발생하는 일반적인 두 가지 문제와 예외 발생 후 올바르게 정리되는 코드를 보여 줍니다.

C# "using" 문을 사용하면 결과적으로 Dispose()가 호출됩니다. 이는 네트워크 오류 발생 시에 예외를 throw할 수 있는 Close()와 동일합니다. "using" 블록의 닫는 중괄호에서 Dispose() 호출이 암시적으로 발생하므로 이 예외 원인은 코드를 작성하는 사용자와 읽는 사용자 모두가 알아차리지 못합니다. 이로 인해 응용 프로그램 오류가 발생할 가능성이 있습니다.

DemonstrateProblemUsingCanThrow 메서드에서 나타나는 첫 번째 문제는 닫는 중괄호로 인해 예외가 throw되고 닫는 중괄호 뒤의 코드가 실행되지 않는다는 것입니다.

using (CalculatorClient client = new CalculatorClient())
{
    ...
} // <-- this line might throw
Console.WriteLine("Hope this code wasn't important, because it might not happen.");

using 블록 안의 어떠한 항목도 예외를 throw하지 않거나 using 블록 안의 모든 예외가 catch될 경우에도 닫는 중괄호에서 암시적 Dispose() 호출이 예외를 throw할 수 있으므로 Console.Writeline이 발생하지 않을 수 있습니다.

DemonstrateProblemUsingCanThrowAndMask 메서드에서 나타나는 두 번째 문제는 예외를 throw하는 닫는 중괄호와 관련된 또 다른 문제입니다.

using (CalculatorClient client = new CalculatorClient())
{
    ...
    throw new ApplicationException("Hope this exception was not important, because "+
                                   "it might be masked by the Close exception.");
} // <-- this line might throw an exception.

Dispose()가 "finally" 블록 안에서 발생하므로 Dispose()가 실패할 경우 ApplicationException은 using 블록 외부에서 표시되지 않습니다. 외부 코드가 ApplicationException이 발생하는 시점을 알아야 할 경우 "using" 구문은 이 예외를 마스킹하여 문제를 일으킬 수 있습니다.

마지막으로 이 샘플에서는 DemonstrateCleanupWithExceptions에 예외가 발생할 경우 올바르게 정리하는 방법을 보여 줍니다. 이를 위해 오류를 보고하고 Abort를 호출하는 try/catch 블록이 사용됩니다. 클라이언트 호출에서 예외를 catch하는 방법에 대한 자세한 내용은 Expected Exceptions 샘플을 참조하십시오.

try
{
    ...
    client.Close();
}
catch (CommunicationException e)
{
    ...
    client.Abort();
}
catch (TimeoutException e)
{
    ...
    client.Abort();
}
catch (Exception e)
{
    ...
    client.Abort();
    throw;
}

참고

using 문 및 ServiceHost: 자체 호스팅되는 대부분의 응용 프로그램은 서비스를 호스팅하는 것 외에 다른 작업을 거의 수행하지 않고 ServiceHost.Close에서 거의 예외를 throw하지 않으므로 이러한 응용 프로그램은 ServiceHost와 함께 using 문을 안전하게 사용할 수 있습니다. 그러나 ServiceHost.Close에서 CommunicationException을 throw할 수 있으므로 ServiceHost를 닫은 후 응용 프로그램이 계속될 경우 using 문을 사용하지 않아야 하고 위에 제공된 패턴을 따라야 합니다.

샘플을 실행하면 작업 응답 및 예외가 클라이언트 콘솔 창에 표시됩니다.

클라이언트 프로세스는 각각 Divide 호출을 시도하는 세 개의 시나리오를 실행합니다. 첫 번째 시나리오는 Dispose()의 예외로 인해 코드를 건너뛰는 것을 보여 줍니다. 두 번째 시나리오는 Dispose()의 예외로 인해 중요한 예외가 마스킹되는 것을 보여 줍니다. 세 번째 시나리오는 올바른 정리를 보여 줍니다.

클라이언트 프로세스로부터의 예상 출력은 다음과 같습니다.

=
= Demonstrating problem:  closing brace of using statement can throw.
=
Got System.ServiceModel.CommunicationException from Divide.
Got System.ServiceModel.Security.MessageSecurityException
=
= Demonstrating problem:  closing brace of using statement can mask other Exceptions.
=
Got System.ServiceModel.CommunicationException from Divide.
Got System.ServiceModel.Security.MessageSecurityException
=
= Demonstrating cleanup with Exceptions.
=
Calling client.Add(0.0, 0.0);
        client.Add(0.0, 0.0); returned 0
Calling client.Divide(0.0, 0.0);
Got System.ServiceModel.CommunicationException from Divide.

Press <ENTER> to terminate client.

샘플을 설치, 빌드 및 실행하려면

  1. Windows Communication Foundation 샘플의 일회 설치 절차를 수행했는지 확인합니다.

  2. C# 또는 Visual Basic .NET 버전의 솔루션을 빌드하려면 Windows Communication Foundation 샘플 빌드의 지침을 따릅니다.

  3. 단일 컴퓨터 또는 다중 컴퓨터 구성에서 샘플을 실행하려면 Windows Communication Foundation 샘플 실행의 지침을 따릅니다.

Send comments about this topic to Microsoft.
© 2007 Microsoft Corporation. All rights reserved.