수색…
기본 예외 처리
try
{
/* code that could throw an exception */
}
catch (Exception ex)
{
/* handle the exception */
}
동일한 코드로 모든 예외를 처리하는 것이 가장 좋은 방법이 아닌 경우가 있습니다.
이는 최후의 수단으로 내부 예외 처리 루틴이 실패 할 때 일반적으로 사용됩니다.
특정 예외 유형 처리
try
{
/* code to open a file */
}
catch (System.IO.FileNotFoundException)
{
/* code to handle the file being not found */
}
catch (System.IO.UnauthorizedAccessException)
{
/* code to handle not being allowed access to the file */
}
catch (System.IO.IOException)
{
/* code to handle IOException or it's descendant other than the previous two */
}
catch (System.Exception)
{
/* code to handle other errors */
}
예외가 순서대로 평가되고 상속이 적용된다는 점에주의하십시오. 그래서 가장 구체적인 것들로 시작해서 그들의 조상과 끝내야합니다. 어느 한 지점에서 하나의 catch 블록 만 실행됩니다.
예외 객체 사용
자신의 코드에서 예외를 생성하고 예외를 throw 할 수 있습니다. 예외를 인스턴스화하는 것은 다른 C # 객체와 동일한 방식으로 수행됩니다.
Exception ex = new Exception();
// constructor with an overload that takes a message string
Exception ex = new Exception("Error message");
그런 다음 throw
키워드를 사용하여 예외를 발생시킬 수 있습니다.
try
{
throw new Exception("Error");
}
catch (Exception ex)
{
Console.Write(ex.Message); // Logs 'Error' to the output window
}
참고 : catch 블록 안에 새로운 예외를 던지려면 원래 예외가 "내부 예외"로 전달되는지 확인하십시오.
void DoSomething()
{
int b=1; int c=5;
try
{
var a = 1;
b = a - 1;
c = a / b;
a = a / c;
}
catch (DivideByZeroException dEx) when (b==0)
{
// we're throwing the same kind of exception
throw new DivideByZeroException("Cannot divide by b because it is zero", dEx);
}
catch (DivideByZeroException dEx) when (c==0)
{
// we're throwing the same kind of exception
throw new DivideByZeroException("Cannot divide by c because it is zero", dEx);
}
}
void Main()
{
try
{
DoSomething();
}
catch (Exception ex)
{
// Logs full error information (incl. inner exception)
Console.Write(ex.ToString());
}
}
이 경우에는 예외를 처리 할 수는 없지만 메시지에 유용한 정보가 추가되어 있다고 가정합니다 (원래 예외는 외부 예외 블록에서 ex.InnerException
을 통해 액세스 할 수 있습니다).
다음과 같이 표시됩니다.
System.DivideByZeroException : 0이므로 b로 나눌 수 없습니다. ---> System.DivideByZeroException : 0으로 나누려고했습니다.
C에서 UserQuery.g__DoSomething0_0 () : [...] \ LINQPadQuery.cs : line 36
--- 내부 예외 스택 추적 끝 ---
C에서 UserQuery.g__DoSomething0_0 () : [...] \ LINQPadQuery.cs : line 42
UserQuery.Main ()에서 C : [...] \ LINQPadQuery.cs : 줄 55
LinqPad에서이 예제를 사용한다면 라인 번호가별로 의미가 없다는 것을 알게 될 것입니다 (항상 도움이되는 것은 아닙니다). 그러나 위에 제시된 유용한 오류 텍스트를 전달하면 오류 위치를 추적하는 데 걸리는 시간이 현저히 줄어 듭니다.이 예제에서는 분명히 선
c = a / b;
함수 DoSomething()
.
마지막으로 블록
try
{
/* code that could throw an exception */
}
catch (Exception)
{
/* handle the exception */
}
finally
{
/* Code that will be executed, regardless if an exception was thrown / caught or not */
}
try / catch / finally
블록은 파일에서 읽을 때 매우 편리 할 수 있습니다.
예 :
FileStream f = null;
try
{
f = File.OpenRead("file.txt");
/* process the file here */
}
finally
{
f?.Close(); // f may be null, so use the null conditional operator.
}
try 블록 뒤에는 catch
또는 finally
블록이 와야합니다. 그러나 catch 블록이 없으므로 실행이 종료됩니다. 종료 전에 finally 블록 내의 명령문이 실행됩니다.
파일 읽기에서 우리는 FileStream
( OpenRead
반환하는 것)으로 using
블록을 사용할 수 있었고 IDisposable
구현했습니다.
try
블록에 return
문이 있더라도 finally
블록은 일반적으로 실행됩니다. 다음과 같은 몇 가지 경우가 있습니다.
- StackOverflow가 발생할 때.
-
Environment.FailFast
- 일반적으로 외부 소스를 통해 응용 프로그램 프로세스가 종료됩니다.
WCF 서비스 용 IErrorHandler 구현
WCF 서비스 용 IErrorHandler를 구현하면 오류 처리 및 로깅을 중앙 집중화 할 수 있습니다. 여기에 표시된 구현은 WCF 서비스 중 하나에 대한 호출의 결과로 발생하는 처리되지 않은 예외를 잡아야합니다. 또한이 예제에서는 사용자 정의 객체를 반환하는 방법과 기본 XML 대신 JSON을 반환하는 방법을 보여줍니다.
IErrorHandler 구현 :
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Runtime.Serialization.Json;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace BehaviorsAndInspectors
{
public class ErrorHandler : IErrorHandler
{
public bool HandleError(Exception ex)
{
// Log exceptions here
return true;
} // end
public void ProvideFault(Exception ex, MessageVersion version, ref Message fault)
{
// Get the outgoing response portion of the current context
var response = WebOperationContext.Current.OutgoingResponse;
// Set the default http status code
response.StatusCode = HttpStatusCode.InternalServerError;
// Add ContentType header that specifies we are using JSON
response.ContentType = new MediaTypeHeaderValue("application/json").ToString();
// Create the fault message that is returned (note the ref parameter) with BaseDataResponseContract
fault = Message.CreateMessage(
version,
string.Empty,
new CustomReturnType { ErrorMessage = "An unhandled exception occurred!" },
new DataContractJsonSerializer(typeof(BaseDataResponseContract), new List<Type> { typeof(BaseDataResponseContract) }));
if (ex.GetType() == typeof(VariousExceptionTypes))
{
// You might want to catch different types of exceptions here and process them differently
}
// Tell WCF to use JSON encoding rather than default XML
var webBodyFormatMessageProperty = new WebBodyFormatMessageProperty(WebContentFormat.Json);
fault.Properties.Add(WebBodyFormatMessageProperty.Name, webBodyFormatMessageProperty);
} // end
} // end class
} // end namespace
이 예제에서는 핸들러를 서비스 비헤이비어에 연결합니다. IEndpointBehavior, IContractBehavior 또는 IOperationBehavior에도 이와 비슷한 방식으로 연결할 수 있습니다.
서비스 동작에 연결 :
using System;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
namespace BehaviorsAndInspectors
{
public class ErrorHandlerExtension : BehaviorExtensionElement, IServiceBehavior
{
public override Type BehaviorType
{
get { return GetType(); }
}
protected override object CreateBehavior()
{
return this;
}
private IErrorHandler GetInstance()
{
return new ErrorHandler();
}
void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { } // end
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
var errorHandlerInstance = GetInstance();
foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
{
dispatcher.ErrorHandlers.Add(errorHandlerInstance);
}
}
void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } // end
} // end class
} // end namespace
Web.config의 구성 :
...
<system.serviceModel>
<services>
<service name="WebServices.MyService">
<endpoint binding="webHttpBinding" contract="WebServices.IMyService" />
</service>
</services>
<extensions>
<behaviorExtensions>
<!-- This extension if for the WCF Error Handling-->
<add name="ErrorHandlerBehavior" type="WebServices.BehaviorsAndInspectors.ErrorHandlerExtensionBehavior, WebServices, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<ErrorHandlerBehavior />
</behavior>
</serviceBehaviors>
</behaviors>
....
</system.serviceModel>
...
다음은이 주제에 도움이되는 몇 가지 링크입니다.
https://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler(v=vs.100).aspx
다른 예 :
HTTP 상태 코드가 401 인 경우 잘못된 메시지 본문을 반환하는 IErrorHandler
IErrorHandler WCF .. 내 오류를 처리하는 것 같지 않습니다 어떤 아이디어?
비 - 확인 HTTP 코드와 JSON 응답을 반환하는 사용자 지정 WCF 오류 처리기를 만드는 방법?
HttpClient 요청에 대해 Content-Type 헤더를 어떻게 설정합니까?
사용자 정의 예외 작성
다른 예외와 마찬가지로 throw 될 수있는 사용자 정의 예외를 구현할 수 있습니다. 이는 런타임 중에 예외를 다른 오류와 구별 할 수 있도록하려는 경우에 유용합니다.
이 예제에서는 복잡한 입력을 구문 분석하는 동안 응용 프로그램에 발생할 수있는 문제를 명확하게 처리하기 위해 사용자 정의 예외를 생성합니다.
사용자 정의 예외 클래스 작성
사용자 정의 예외를 작성하려면 Exception
의 서브 클래스를 작성하십시오.
public class ParserException : Exception
{
public ParserException() :
base("The parsing went wrong and we have no additional information.") { }
}
사용자 정의 예외는 포수에 추가 정보를 제공하려는 경우 매우 유용합니다.
public class ParserException : Exception
{
public ParserException(string fileName, int lineNumber) :
base($"Parser error in {fileName}:{lineNumber}")
{
FileName = fileName;
LineNumber = lineNumber;
}
public string FileName {get; private set;}
public int LineNumber {get; private set;}
}
자, catch(ParserException x)
를 catch(ParserException x)
했을 때에, 예외 처리를 미세 조정하기위한 추가의 시멘틱스가 catch(ParserException x)
.
사용자 지정 클래스는 다음과 같은 기능을 구현하여 추가 시나리오를 지원할 수 있습니다.
다시 던지는
구문 분석 프로세스 중에 원래 예외는 여전히 중요합니다. 이 예제에서는 코드가 숫자 일 것으로 예상되는 문자열을 구문 분석하려고하기 때문에 FormatException
입니다. 이 경우 사용자 정의 예외는 ' InnerException '의 포함을 지원해야합니다.
//new constructor:
ParserException(string msg, Exception inner) : base(msg, inner) {
}
직렬화
경우에 따라 예외가 AppDomain 경계를 넘을 수 있습니다. 파서가 새 파서 구성을 빠르게 다시로드 할 수 있도록 자체 AppDomain에서 실행중인 경우입니다. Visual Studio에서 Exception
템플릿을 사용하여 이와 같은 코드를 생성 할 수 있습니다.
[Serializable]
public class ParserException : Exception
{
// Constructor without arguments allows throwing your exception without
// providing any information, including error message. Should be included
// if your exception is meaningful without any additional details. Should
// set message by calling base constructor (default message is not helpful).
public ParserException()
: base("Parser failure.")
{}
// Constructor with message argument allows overriding default error message.
// Should be included if users can provide more helpful messages than
// generic automatically generated messages.
public ParserException(string message)
: base(message)
{}
// Constructor for serialization support. If your exception contains custom
// properties, read their values here.
protected ParserException(SerializationInfo info, StreamingContext context)
: base(info, context)
{}
}
ParserException의 사용
try
{
Process.StartRun(fileName)
}
catch (ParserException ex)
{
Console.WriteLine($"{ex.Message} in ${ex.FileName}:${ex.LineNumber}");
}
catch (PostProcessException x)
{
...
}
catch 및 wrapping 예외에 대한 사용자 정의 예외를 사용할 수도 있습니다. 이 방법으로 많은 다른 오류를 응용 프로그램에서보다 유용한 단일 오류 유형으로 변환 할 수 있습니다.
try
{
int foo = int.Parse(token);
}
catch (FormatException ex)
{
//Assuming you added this constructor
throw new ParserException(
$"Failed to read {token} as number.",
FileName,
LineNumber,
ex);
}
사용자 정의 예외를 발생시켜 예외를 처리 할 때는 일반적으로 위에 표시된 것처럼 원래 예외를 InnerException
특성에 참조해야합니다.
보안 문제
사용자가 애플리케이션의 내부 동작을 볼 수 있도록하여 예외가 발생한 이유가 보안을 손상시킬 수있는 경우 내부 예외를 래핑하는 것은 좋지 않을 수 있습니다. 이것은 다른 사람들이 사용할 클래스 라이브러리를 생성하는 경우에 적용될 수 있습니다.
다음은 내부 예외를 래핑하지 않고 사용자 정의 예외를 발생시키는 방법입니다.
try
{
// ...
}
catch (SomeStandardException ex)
{
// ...
throw new MyCustomException(someMessage);
}
결론
랩핑 또는 언 래핑 된 새 예외가있는 사용자 정의 예외를 발생시킬 때 호출자에게 의미있는 예외를 발생시켜야합니다. 예를 들어, 클래스 라이브러리의 사용자는 해당 라이브러리가 내부 작업을 수행하는 방법에 대해 많이 알지 못할 수 있습니다. 클래스 라이브러리의 종속성에 의해 발생하는 예외는 의미가 없습니다. 오히려, 사용자는 클래스 라이브러리가 이러한 종속성을 잘못된 방식으로 사용하는 것과 관련된 예외를 원합니다.
try
{
// ...
}
catch (IOException ex)
{
// ...
throw new StorageServiceException(@"The Storage Service encountered a problem saving
your data. Please consult the inner exception for technical details.
If you are not able to resolve the problem, please call 555-555-1234 for technical
assistance.", ex);
}
예외 방지 패턴
삼키는 예외
하나는 항상 다음과 같은 방법으로 예외를 다시 throw해야합니다.
try
{
...
}
catch (Exception ex)
{
...
throw;
}
아래처럼 예외를 다시 던지면 원래 예외가 난독 화되어 원래 스택 추적을 잃게됩니다. 하나는 이것을해서는 안됩니다! catch 및 rethrow 이전의 스택 추적은 손실됩니다.
try
{
...
}
catch (Exception ex)
{
...
throw ex;
}
야구 예외 처리
if-then 문과 while 루프와 같은 정상적인 흐름 제어 구문 대신 예외를 사용해서는 안됩니다. 이 반 패턴은 때때로 Baseball Exception Handling 이라고 불립니다.
다음은 안티 패턴의 예입니다.
try
{
while (AccountManager.HasMoreAccounts())
{
account = AccountManager.GetNextAccount();
if (account.Name == userName)
{
//We found it
throw new AccountFoundException(account);
}
}
}
catch (AccountFoundException found)
{
Console.Write("Here are your account details: " + found.Account.Details.ToString());
}
다음은 더 좋은 방법입니다.
Account found = null;
while (AccountManager.HasMoreAccounts() && (found==null))
{
account = AccountManager.GetNextAccount();
if (account.Name == userName)
{
//We found it
found = account;
}
}
Console.Write("Here are your account details: " + found.Details.ToString());
잡기 (예외)
코드에서 일반적인 예외 유형을 잡는 이유는 거의 없습니다 (일부는 없다!). 코드에서 버그를 숨기려면 예외 유형 만 잡아야합니다.
try
{
var f = File.Open(myfile);
// do something
}
catch (Exception x)
{
// Assume file not found
Console.Write("Could not open file");
// but maybe the error was a NullReferenceException because of a bug in the file handling code?
}
더 나은 방법 :
try
{
var f = File.Open(myfile);
// do something which should normally not throw exceptions
}
catch (IOException)
{
Console.Write("File not found");
}
// Unfortunatelly, this one does not derive from the above, so declare separatelly
catch (UnauthorizedAccessException)
{
Console.Write("Insufficient rights");
}
다른 예외가 발생하면 우리는 의도적으로 응용 프로그램을 중단 시키므로 디버거에서 직접 단계를 밟아 문제를 해결할 수 있습니다. 우리는 어쨌든 이러한 예외가 발생하지 않는 프로그램을 출시해서는 안되기 때문에 충돌을 일으키지 않아도됩니다.
다음은 프로그래밍 오류를 해결하기 위해 예외를 사용하기 때문에 나쁜 예입니다. 그건 그들이 설계 한 것이 아닙니다.
public void DoSomething(String s)
{
if (s == null)
throw new ArgumentNullException(nameof(s));
// Implementation goes here
}
try
{
DoSomething(myString);
}
catch(ArgumentNullException x)
{
// if this happens, we have a programming error and we should check
// why myString was null in the first place.
}
한 가지 방법으로 발생한 예외 / 여러 예외
누가 한 가지 방법으로 여러 가지 예외를 던질 수 없다고합니다. AggregateExceptions에 익숙하지 않은 독자는 자신의 데이터 구조를 만들어 유추 할 수 있습니다. 물론 예외가 아닌 다른 데이터 구조가 유효성 검사의 결과와 같이 더 이상적 일 것입니다. AggregateExceptions를 가지고 게임을하는 경우에도 수신 측에있을 수 있으며 항상이를 처리하지 못할 수 있습니다.
메소드를 실행하는 것은 매우 합당합니다. 전체적으로 실패가 발생하더라도 던져진 예외에서 잘못 처리 된 여러 가지 사항을 강조해야합니다. 예를 들어, Parallel 메소드가 여러 스레드로 분할 된 태스크와 여러 스레드가 예외를 throw 할 수있는 방식으로이 동작을 볼 수 있으며이를보고해야합니다. 다음과 같은 이점을 누릴 수있는 어리석은 예가 있습니다.
public void Run()
{
try
{
this.SillyMethod(1, 2);
}
catch (AggregateException ex)
{
Console.WriteLine(ex.Message);
foreach (Exception innerException in ex.InnerExceptions)
{
Console.WriteLine(innerException.Message);
}
}
}
private void SillyMethod(int input1, int input2)
{
var exceptions = new List<Exception>();
if (input1 == 1)
{
exceptions.Add(new ArgumentException("I do not like ones"));
}
if (input2 == 2)
{
exceptions.Add(new ArgumentException("I do not like twos"));
}
if (exceptions.Any())
{
throw new AggregateException("Funny stuff happended during execution", exceptions);
}
}
예외 중첩 및 catch 블록 시도
하나는 둥지 한 가지 예외 / 할 수있는 try
catch
다른 내부 블록.
이렇게하면 전체 메커니즘을 방해하지 않고 작업 할 수있는 작은 코드 블록을 관리 할 수 있습니다.
try
{
//some code here
try
{
//some thing which throws an exception. For Eg : divide by 0
}
catch (DivideByZeroException dzEx)
{
//handle here only this exception
//throw from here will be passed on to the parent catch block
}
finally
{
//any thing to do after it is done.
}
//resume from here & proceed as normal;
}
catch(Exception e)
{
//handle here
}
참고 : 부모 catch 블록에 던져 넣을 때 예외 를 삼가는 것을 피하십시오
모범 사례
컨닝 지
해야 할 것 | 하지 마라. |
---|---|
제어문을 통한 제어 흐름 | 예외가있는 제어 흐름 |
기록에 의해 무시 된 (흡수 된) 예외를 추적하십시오. | 예외 무시 |
throw 를 사용하여 예외를 반복합니다. | Re-throw exception - throw new ArgumentNullException() throw ex |
미리 정의 된 시스템 예외 발생 | 미리 정의 된 시스템 예외와 유사한 사용자 정의 예외를 발생시킵니다. |
응용 프로그램 논리가 중요 할 경우 사용자 정의 / 미리 정의 된 예외를 발생시킵니다. | 흐름에 경고를 표시하기 위해 사용자 정의 / 미리 정의 된 예외를 발생시킵니다. |
처리하려는 예외를 잡아라. | 모든 예외를 잡아라. |
예외가있는 비즈니스 로직을 관리하지 마십시오.
흐름 제어는 예외로해서는 안됩니다. 대신 조건문을 사용하십시오. 제어가 if-else
문으로 명확하게 수행 될 수 if-else
가독성과 성능이 저하되므로 예외를 사용하지 마십시오.
Mr. Bad Practices의 다음 스 니펫을 고려하십시오.
// This is a snippet example for DO NOT
object myObject;
void DoingSomethingWithMyObject()
{
Console.WriteLine(myObject.ToString());
}
실행이 Console.WriteLine(myObject.ToString());
도달하면 Console.WriteLine(myObject.ToString());
응용 프로그램이 NullReferenceException을 throw합니다. Mr. Bad Practice는 myObject
가 null이며 catch & handle 처리를 위해 스 니펫을 편집 함 NullReferenceException
:
// This is a snippet example for DO NOT
object myObject;
void DoingSomethingWithMyObject()
{
try
{
Console.WriteLine(myObject.ToString());
}
catch(NullReferenceException ex)
{
// Hmmm, if I create a new instance of object and assign it to myObject:
myObject = new object();
// Nice, now I can continue to work with myObject
DoSomethingElseWithMyObject();
}
}
이전 스 니펫은 예외 논리만을 다루기 때문에 myObject
가 null이 아닌 경우 어떻게해야합니까? 논리의이 부분을 어디에서 다루어야합니까? Console.WriteLine(myObject.ToString());
바로 다음에 있습니다 Console.WriteLine(myObject.ToString());
? try...catch
블록을 어때?
Mr. Best Practices는 어떻습니까? 어떻게 처리할까요?
// This is a snippet example for DO
object myObject;
void DoingSomethingWithMyObject()
{
if(myObject == null)
myObject = new object();
// When execution reaches this point, we are sure that myObject is not null
DoSomethingElseWithMyObject();
}
Mr. Best Practices는 동일한 논리를보다 적은 코드와 명확하고 이해하기 쉬운 논리로 구현했습니다.
예외를 다시 throw하지 마십시오.
예외를 다시 던지는 것은 비용이 많이 듭니다. 성능에 부정적인 영향을줍니다. 일상적으로 실패하는 코드의 경우 디자인 패턴을 사용하여 성능 문제를 최소화 할 수 있습니다. 이 항목에서는 예외가 성능에 큰 영향을 줄 때 유용 할 수있는 두 가지 디자인 패턴에 대해 설명합니다.
로깅없이 예외를 흡수하지 마십시오.
try
{
//Some code that might throw an exception
}
catch(Exception ex)
{
//empty catch block, bad practice
}
예외를 삼키지 마십시오. 예외를 무시하면 그 순간을 저장하지만 나중에 유지 보수를 위해 혼란을 야기 할 것입니다. 예외를 로깅 할 때는 항상 예외 인스턴스를 기록하여 전체 스택 추적이 기록되고 예외 메시지 만 기록되지 않도록해야합니다.
try
{
//Some code that might throw an exception
}
catch(NullException ex)
{
LogManager.Log(ex.ToString());
}
처리 할 수없는 예외를 잡지 마십시오.
같은 많은 자원 이 하나 , 강하게 당신이 당신이 그것을 잡기하는 장소에서 예외를 잡는 이유를 고려하도록 촉구한다. 해당 위치에서 처리 할 수있는 경우에만 예외를 catch해야합니다. 다른 알고리즘을 시도하거나, 백업 데이터베이스에 연결하거나, 다른 파일 이름을 시도하거나, 30 초 동안 기다렸다가 다시 시도하거나 관리자에게 알리는 것과 같이 문제를 완화하기 위해 문제를 해결할 수 있다면 문제를 해결하고이를 수행 할 수 있습니다. 당신이 그럴 듯하고 합리적으로 할 수있는 일이 없다면, 그냥 "놓아 버려"예외를 더 높은 차원에서 다루도록하십시오. 예외가 충분히 비극적이며 문제의 심각성으로 인해 전체 프로그램이 충돌하는 것 이외의 합리적인 선택이없는 경우 충돌이 발생하게하십시오.
try
{
//Try to save the data to the main database.
}
catch(SqlException ex)
{
//Try to save the data to the alternative database.
}
//If anything other than a SqlException is thrown, there is nothing we can do here. Let the exception bubble up to a level where it can be handled.
처리되지 않은 스레드 예외
AppDomain.UnhandledException 이 이벤트는 캐치되지 않은 예외에 대한 알림을 제공합니다. 시스템 기본 처리기가 예외를 사용자에게보고하고 응용 프로그램을 종료하기 전에 응용 프로그램에서 예외에 대한 정보를 기록 할 수 있습니다. 응용 프로그램의 상태에 대한 충분한 정보가 있으면 다른 나중에 복구 할 수 있도록 프로그램 데이터를 저장하는 등의 작업을 수행 할 수 있습니다. 예외가 처리되지 않으면 프로그램 데이터가 손상 될 수 있으므로주의해야합니다.
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledException);
}
Application.ThreadException 이 이벤트를 사용하면 Windows Forms 응용 프로그램에서 Windows Forms 스레드에서 발생하는 처리되지 않은 예외를 처리 할 수 있습니다. 이벤트 처리기를 ThreadException 이벤트에 연결하여 이러한 예외를 처리하면 응용 프로그램을 알 수없는 상태로 둡니다. 가능하면 예외는 구조화 된 예외 처리 블록에서 처리해야합니다.
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledException);
Application.ThreadException += new ThreadExceptionEventHandler(ThreadException);
}
그리고 마지막으로 예외 처리
static void UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = (Exception)e.ExceptionObject;
// your code
}
static void ThreadException(object sender, ThreadExceptionEventArgs e)
{
Exception ex = e.Exception;
// your code
}
예외를 던집니다.
비정상적인 일이 생길 때 코드에서 예외를 throw 할 수 있으며 종종 그렇게해야합니다.
public void WalkInto(Destination destination)
{
if (destination.Name == "Mordor")
{
throw new InvalidOperationException("One does not simply walk into Mordor.");
}
// ... Implement your normal walking code here.
}