System.Exception 클래스
이 문서에서는 이 API에 대한 참조 설명서에 대한 추가 설명서를 제공합니다.
Exception 클래스는 모든 예외의 기본 클래스입니다. 오류가 발생 하는 시스템 또는 현재 실행 중인 애플리케이션 오류에 대 한 정보를 포함 하는 예외를 throw 하 여 보고 합니다. 예외가 throw 되 면 애플리케이션에서 또는 기본 예외 핸들러에서 처리 됩니다.
오류 및 예외
런타임 오류는 다양한 이유로 발생할 수 있습니다. 그러나 코드에서 모든 오류를 예외로 처리해야 하는 것은 아닙니다. 다음은 런타임에 발생할 수 있는 오류의 몇 가지 범주와 이에 대응하는 적절한 방법입니다.
사용 오류입니다. 사용 오류는 예외가 발생할 수 있는 프로그램 논리의 오류를 나타냅니다. 그러나 오류는 예외 처리를 통해서가 아니라 잘못된 코드를 수정하여 해결해야 합니다. 예를 들어 다음 예제에서 메서드의 재정의 Object.Equals(Object) 는 인수가 항상 null이
obj
아니어야 한다고 가정합니다.using System; public class Person1 { private string _name; public string Name { get { return _name; } set { _name = value; } } public override int GetHashCode() { return this.Name.GetHashCode(); } public override bool Equals(object obj) { // This implementation contains an error in program logic: // It assumes that the obj argument is not null. Person1 p = (Person1) obj; return this.Name.Equals(p.Name); } } public class UsageErrorsEx1 { public static void Main() { Person1 p1 = new Person1(); p1.Name = "John"; Person1 p2 = null; // The following throws a NullReferenceException. Console.WriteLine("p1 = p2: {0}", p1.Equals(p2)); } }
// In F#, null is not a valid state for declared types // without 'AllowNullLiteralAttribute' [<AllowNullLiteral>] type Person() = member val Name = "" with get, set override this.GetHashCode() = this.Name.GetHashCode() override this.Equals(obj) = // This implementation contains an error in program logic: // It assumes that the obj argument is not null. let p = obj :?> Person this.Name.Equals p.Name let p1 = Person() p1.Name <- "John" let p2: Person = null // The following throws a NullReferenceException. printfn $"p1 = p2: {p1.Equals p2}"
Public Class Person Private _name As String Public Property Name As String Get Return _name End Get Set _name = value End Set End Property Public Overrides Function Equals(obj As Object) As Boolean ' This implementation contains an error in program logic: ' It assumes that the obj argument is not null. Dim p As Person = CType(obj, Person) Return Me.Name.Equals(p.Name) End Function End Class Module Example2 Public Sub Main() Dim p1 As New Person() p1.Name = "John" Dim p2 As Person = Nothing ' The following throws a NullReferenceException. Console.WriteLine("p1 = p2: {0}", p1.Equals(p2)) End Sub End Module
재정의 NullReferenceException 를
obj
호출 Object.Equals 한 다음 다시 컴파일하기 전에 null을 명시적으로 테스트하도록 소스 코드를 수정하여 결과를 제거할 수 있는 예외입니다null
. 다음 예제에는 인수를 처리하는 수정된 소스 코드가 포함되어 있습니다null
.using System; public class Person2 { private string _name; public string Name { get { return _name; } set { _name = value; } } public override int GetHashCode() { return this.Name.GetHashCode(); } public override bool Equals(object obj) { // This implementation handles a null obj argument. Person2 p = obj as Person2; if (p == null) return false; else return this.Name.Equals(p.Name); } } public class UsageErrorsEx2 { public static void Main() { Person2 p1 = new Person2(); p1.Name = "John"; Person2 p2 = null; Console.WriteLine("p1 = p2: {0}", p1.Equals(p2)); } } // The example displays the following output: // p1 = p2: False
// In F#, null is not a valid state for declared types // without 'AllowNullLiteralAttribute' [<AllowNullLiteral>] type Person() = member val Name = "" with get, set override this.GetHashCode() = this.Name.GetHashCode() override this.Equals(obj) = // This implementation handles a null obj argument. match obj with | :? Person as p -> this.Name.Equals p.Name | _ -> false let p1 = Person() p1.Name <- "John" let p2: Person = null printfn $"p1 = p2: {p1.Equals p2}" // The example displays the following output: // p1 = p2: False
Public Class Person2 Private _name As String Public Property Name As String Get Return _name End Get Set _name = Value End Set End Property Public Overrides Function Equals(obj As Object) As Boolean ' This implementation handles a null obj argument. Dim p As Person2 = TryCast(obj, Person2) If p Is Nothing Then Return False Else Return Me.Name.Equals(p.Name) End If End Function End Class Module Example3 Public Sub Main() Dim p1 As New Person2() p1.Name = "John" Dim p2 As Person2 = Nothing Console.WriteLine("p1 = p2: {0}", p1.Equals(p2)) End Sub End Module ' The example displays the following output: ' p1 = p2: False
사용 오류에 예외 처리를 사용하는 대신 디버그 빌드에서 사용 오류를 식별하는 방법과 디버그 및 Trace.Assert 릴리스 빌드 모두에서 사용 오류를 식별하는 방법을 사용할 Debug.Assert 수 있습니다. 자세한 내용은 관리 코드의 어설션을 참조하세요.
프로그램 오류입니다. 프로그램 오류는 버그 없는 코드를 작성하여 반드시 피할 수 없는 런타임 오류입니다.
경우에 따라 프로그램 오류는 예상 또는 일상적인 오류 조건을 반영할 수 있습니다. 이 경우 예외 처리를 사용하여 프로그램 오류를 처리하지 않고 작업을 다시 시도하는 것이 좋습니다. 예를 들어 사용자가 특정 형식으로 날짜를 입력해야 하는 경우 메서드를 호출 DateTime.TryParseExact 하여 날짜 문자열을 구문 분석할 수 있습니다. 이 메서드는 메서드를 사용하는 DateTime.ParseExact 대신 구문 분석 작업이 성공했는지 여부를 나타내는 값을 반환 Boolean 합니다. 이 값은 날짜 문자열을 값으로 변환할 수 없는 경우 예외를 DateTime throw합니다FormatException. 마찬가지로, 사용자가 존재하지 않는 파일을 열려고 하면 먼저 메서드를 호출 File.Exists 하여 파일이 있는지 여부를 검사, 파일이 없는 경우 만들 것인지 묻는 메시지를 표시할 수 있습니다.
다른 경우에 프로그램 오류는 코드에서 처리할 수 있는 예기치 않은 오류 조건을 반영합니다. 예를 들어 파일이 있는지 확인하기 위해 검사 있더라도 파일을 열기 전에 삭제되거나 손상되었을 수 있습니다. 이 경우 개체를 인스턴스화하거나 메서드를 StreamReader 호출하여 파일을 열려고 하면 예외가 OpenFileNotFoundException 발생할 수 있습니다. 이러한 경우 예외 처리를 사용하여 오류에서 복구해야 합니다.
시스템 오류. 시스템 오류는 의미 있는 방식으로 프로그래밍 방식으로 처리할 수 없는 런타임 오류입니다. 예를 들어 공용 언어 런타임에서 추가 메모리를 OutOfMemoryException 할당할 수 없는 경우 모든 메서드에서 예외를 throw할 수 있습니다. 일반적으로 시스템 오류는 예외 처리를 사용하여 처리되지 않습니다. 대신,와 같은 이벤트를 사용할 수 있습니다 AppDomain.UnhandledException 호출을 Environment.FailFast 예외 정보를 기록 하 고 애플리케이션을 종료 하기 전에 실패의 사용자에 게 알릴 방법입니다.
블록 시도/catch
공용 언어 런타임은 예외를 개체로 표현하고 프로그램 코드와 예외 처리 코드를 블록과 catch
블록으로 try
분리하는 예외 처리 모델을 제공합니다. 각각 특정 유형의 예외를 처리하도록 설계된 하나 이상의 catch
블록 또는 다른 블록보다 더 구체적인 예외를 catch하도록 설계된 하나의 블록이 있을 수 있습니다.
내 코드에 존재 해야 애플리케이션의 애플리케이션 코드 블록을 실행 하는 동안 발생 하는 예외를 처리 하는 경우는 try
문 이라고는 try
블록입니다. throw 된 예외를 처리 하는 애플리케이션 코드를 try
블록 내에 배치 됩니다는 catch
문 라고는 catch
블록입니다. 0개 이상의 catch
블록이 블록과 try
연결되며 각 catch
블록에는 블록이 처리하는 예외 유형을 결정하는 형식 필터가 포함됩니다.
예외가 발생 하는 경우는 try
블록에 시스템 연결 된 검색 catch
블록을 찾을 때까지 애플리케이션 코드에 나타나는 순서에는 catch
예외를 처리 하는 블록입니다. 블록은 catch
catch 블록의 형식 T
필터가 지정 T
하거나 파생되는 형식인 경우 형식의 예외를 T
처리합니다. 시스템에서 예외를 처리하는 첫 번째 catch
블록을 찾은 후 검색을 중지합니다. 이러한 이유로 애플리케이션 코드를 catch
전에 형식을 처리 하는 블록을 지정 해야 합니다는 catch
이 섹션에 나오는 예제에서 설명한 것 처럼 해당 기본 형식으로 처리 하는 블록. 마지막으로 핸들을 지정하는 System.Exception
catch 블록입니다.
현재 try
블록과 연결된 블록 중 catch
어느 것도 예외를 처리하지 않고 현재 블록이 현재 try
호출 catch
의 다른 try
블록 내에 중첩되면 다음 바깥쪽 try
블록과 연결된 블록이 검색됩니다. 예외에 대한 블록이 없 catch
으면 시스템은 현재 호출에서 이전 중첩 수준을 검색합니다. 현재 호출에서 예외에 대한 블록이 없 catch
으면 예외가 호출 스택 위로 전달되고 이전 스택 프레임은 예외를 catch
처리하는 블록을 검색합니다. 호출 스택의 검색은 예외가 처리되거나 호출 스택에 더 이상 프레임이 없을 때까지 계속됩니다. 찾지 못한 채 호출 스택의 위쪽에 도달 하면는 catch
기본 예외 핸들러가 예외를 처리 하는 블록을 처리 하 고 애플리케이션을 종료 합니다.
F# try.. with 식
F#은 블록을 사용하지 catch
않습니다. 대신, 발생한 예외는 단일 with
블록을 사용하여 패턴과 일치합니다. 문이 아닌 식이므로 모든 경로가 동일한 형식을 반환해야 합니다. 자세히 알아보려면 시도...를 참조 하세요. 식과 함께 사용합니다.
예외 유형 기능
예외 유형은 다음 기능을 지원합니다.
오류를 설명하는 사람이 읽을 수 있는 텍스트입니다. 예외가 발생하면 런타임에서 사용자에게 오류의 특성을 알리고 문제를 해결하기 위한 작업을 제안하는 문자 메시지를 사용할 수 있게 합니다. 이 문자 메시지는 예외 개체의 Message 속성에 보관됩니다. 예외 개체를 만드는 동안 해당 특정 예외의 세부 정보를 설명하는 텍스트 문자열을 생성자에 전달할 수 있습니다. 생성자에 오류 메시지 인수가 제공되지 않으면 기본 오류 메시지가 사용됩니다. 자세한 내용은 Message 속성을 참조하세요.
예외가 throw된 호출 스택의 상태입니다. 이 속성은 StackTrace 코드에서 오류가 발생하는 위치를 확인하는 데 사용할 수 있는 스택 추적을 전달합니다. 스택 추적에는 호출된 모든 메서드와 호출이 이루어지는 원본 파일의 줄 번호가 나열됩니다.
예외 클래스 속성
클래스에는 Exception 코드 위치, 형식, 도움말 파일 및 예외 HelpLinkStackTraceMessageDataInnerExceptionHResultSourceTargetSite이유를 식별하는 데 도움이 되는 다양한 속성이 포함됩니다.
두 개 이상의 예외 사이에 인과 관계가 있는 경우 속성은 InnerException 이 정보를 기본. 외부 예외는 이 내부 예외에 대한 응답으로 throw됩니다. 외부 예외를 처리하는 코드는 이전 내부 예외의 정보를 사용하여 오류를 보다 적절하게 처리할 수 있습니다. 예외에 대한 추가 정보는 속성에 키/값 쌍의 컬렉션으로 저장할 수 있습니다 Data .
예외 개체를 만드는 동안 생성자에 전달되는 오류 메시지 문자열은 지역화되어야 하며 클래스를 사용하여 ResourceManager 리소스 파일에서 제공할 수 있습니다. 지역화된 리소스에 대한 자세한 내용은 위성 어셈블리 만들기 및 리소스 패키징 및 배포 항목을 참조하세요.
사용자에게 예외가 발생한 이유에 대한 광범위한 정보를 제공하기 위해 속성은 HelpLink 도움말 파일에 대한 URL(또는 URN)을 보유할 수 있습니다.
클래스는 Exception 값이 0x80131500 HRESULT COR_E_EXCEPTION
를 사용합니다.
클래스 인스턴스 Exception 의 초기 속성 값 목록은 생성자를 참조 Exception 하세요.
성능 고려 사항
예외를 throw하거나 처리하면 상당한 양의 시스템 리소스와 실행 시간이 사용됩니다. 예측 가능한 이벤트 또는 흐름 제어를 처리하지 않고 진정으로 특별한 조건을 처리하기 위해서만 예외를 throw합니다. 예를 들어 클래스 라이브러리를 개발할 때와 같은 경우에 메서드 인수가 유효하지 않은 경우 유효한 매개 변수를 사용하여 메서드를 호출해야 하므로 예외를 throw하는 것이 합리적입니다. 잘못된 메서드 인수가 사용 오류의 결과가 아닌 경우 특별한 문제가 발생했음을 의미합니다. 반대로, 사용자가 잘못된 데이터를 입력할 것으로 예상할 수 있으므로 사용자 입력이 잘못된 경우 예외를 throw하지 마세요. 대신 사용자가 유효한 입력을 입력할 수 있도록 재시도 메커니즘을 제공합니다. 예외를 사용하여 사용 오류를 처리해서는 안 됩니다. 대신 어설션을 사용하여 사용 오류를 식별하고 수정합니다.
또한 반환 코드가 충분한 경우 예외를 throw하지 마세요. 반환 코드를 예외로 변환하지 마세요. 은 정기적으로 예외를 catch하지 않고 무시한 다음 처리를 계속합니다.
예외 다시 throw
대부분의 경우 예외 처리기는 예외를 호출자에게 전달하려고 합니다. 이 문제는 다음에서 가장 자주 발생합니다.
.NET 클래스 라이브러리 또는 다른 클래스 라이브러리의 메서드에 대한 호출을 차례로 래핑하는 클래스 라이브러리입니다.
애플리케이션 또는 심각한 예외를 발생 하는 라이브러리입니다. 예외 처리기는 예외를 기록한 다음 예외를 다시 throw할 수 있습니다.
예외를 다시 throw하는 권장 방법은 단순히 C#의 throw 문, F#의 reraise 함수 및 식을 포함하지 않고 Visual Basic의 Throw 문을 사용하는 것입니다. 이렇게 하면 예외가 호출자에게 전파될 때 모든 호출 스택 정보가 유지됩니다. 다음 예제에서는 이것을 보여 줍니다. 문자열 확장 메서드 FindOccurrences
는 인수의 유효성을 미리 검사하지 않고 하나 이상의 호출 String.IndexOf(String, Int32) 을 래핑합니다.
using System;
using System.Collections.Generic;
public static class Library1
{
public static int[] FindOccurrences(this String s, String f)
{
var indexes = new List<int>();
int currentIndex = 0;
try
{
while (currentIndex >= 0 && currentIndex < s.Length)
{
currentIndex = s.IndexOf(f, currentIndex);
if (currentIndex >= 0)
{
indexes.Add(currentIndex);
currentIndex++;
}
}
}
catch (ArgumentNullException)
{
// Perform some action here, such as logging this exception.
throw;
}
return indexes.ToArray();
}
}
open System
module Library =
let findOccurrences (s: string) (f: string) =
let indexes = ResizeArray()
let mutable currentIndex = 0
try
while currentIndex >= 0 && currentIndex < s.Length do
currentIndex <- s.IndexOf(f, currentIndex)
if currentIndex >= 0 then
indexes.Add currentIndex
currentIndex <- currentIndex + 1
with :? ArgumentNullException ->
// Perform some action here, such as logging this exception.
reraise ()
indexes.ToArray()
Imports System.Collections.Generic
Imports System.Runtime.CompilerServices
Public Module Library
<Extension()>
Public Function FindOccurrences1(s As String, f As String) As Integer()
Dim indexes As New List(Of Integer)
Dim currentIndex As Integer = 0
Try
Do While currentIndex >= 0 And currentIndex < s.Length
currentIndex = s.IndexOf(f, currentIndex)
If currentIndex >= 0 Then
indexes.Add(currentIndex)
currentIndex += 1
End If
Loop
Catch e As ArgumentNullException
' Perform some action here, such as logging this exception.
Throw
End Try
Return indexes.ToArray()
End Function
End Module
그런 다음 호출자가 두 번 호출합니다 FindOccurrences
. 두 번째 호출 FindOccurrences
에서 호출자는 검색 문자열로 전달 null
되어 메서드가 String.IndexOf(String, Int32) 예외를 ArgumentNullException throw합니다. 이 예외는 메서드에서 FindOccurrences
처리되고 호출자에게 다시 전달됩니다. throw 문은 식 없이 사용되므로 예제의 출력은 호출 스택이 유지됨을 보여줍니다.
public class RethrowEx1
{
public static void Main()
{
String s = "It was a cold day when...";
int[] indexes = s.FindOccurrences("a");
ShowOccurrences(s, "a", indexes);
Console.WriteLine();
String toFind = null;
try
{
indexes = s.FindOccurrences(toFind);
ShowOccurrences(s, toFind, indexes);
}
catch (ArgumentNullException e)
{
Console.WriteLine("An exception ({0}) occurred.",
e.GetType().Name);
Console.WriteLine("Message:\n {0}\n", e.Message);
Console.WriteLine("Stack Trace:\n {0}\n", e.StackTrace);
}
}
private static void ShowOccurrences(String s, String toFind, int[] indexes)
{
Console.Write("'{0}' occurs at the following character positions: ",
toFind);
for (int ctr = 0; ctr < indexes.Length; ctr++)
Console.Write("{0}{1}", indexes[ctr],
ctr == indexes.Length - 1 ? "" : ", ");
Console.WriteLine();
}
}
// The example displays the following output:
// 'a' occurs at the following character positions: 4, 7, 15
//
// An exception (ArgumentNullException) occurred.
// Message:
// Value cannot be null.
// Parameter name: value
//
// Stack Trace:
// at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
// ngComparison comparisonType)
// at Library.FindOccurrences(String s, String f)
// at Example.Main()
open Library
let showOccurrences toFind (indexes: int[]) =
printf $"'{toFind}' occurs at the following character positions: "
for i = 0 to indexes.Length - 1 do
printf $"""{indexes[i]}{if i = indexes.Length - 1 then "" else ", "}"""
printfn ""
let s = "It was a cold day when..."
let indexes = findOccurrences s "a"
showOccurrences "a" indexes
printfn ""
let toFind: string = null
try
let indexes = findOccurrences s toFind
showOccurrences toFind indexes
with :? ArgumentNullException as e ->
printfn $"An exception ({e.GetType().Name}) occurred."
printfn $"Message:\n {e.Message}\n"
printfn $"Stack Trace:\n {e.StackTrace}\n"
// The example displays the following output:
// 'a' occurs at the following character positions: 4, 7, 15
//
// An exception (ArgumentNullException) occurred.
// Message:
// Value cannot be null. (Parameter 'value')
//
// Stack Trace:
// at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
// ngComparison comparisonType)
// at Library.findOccurrences(String s, String f)
// at <StartupCode$fs>.main@()
Module Example1
Public Sub Main()
Dim s As String = "It was a cold day when..."
Dim indexes() As Integer = s.FindOccurrences1("a")
ShowOccurrences(s, "a", indexes)
Console.WriteLine()
Dim toFind As String = Nothing
Try
indexes = s.FindOccurrences1(toFind)
ShowOccurrences(s, toFind, indexes)
Catch e As ArgumentNullException
Console.WriteLine("An exception ({0}) occurred.",
e.GetType().Name)
Console.WriteLine("Message:{0} {1}{0}", vbCrLf, e.Message)
Console.WriteLine("Stack Trace:{0} {1}{0}", vbCrLf, e.StackTrace)
End Try
End Sub
Private Sub ShowOccurrences(s As String, toFind As String, indexes As Integer())
Console.Write("'{0}' occurs at the following character positions: ",
toFind)
For ctr As Integer = 0 To indexes.Length - 1
Console.Write("{0}{1}", indexes(ctr),
If(ctr = indexes.Length - 1, "", ", "))
Next
Console.WriteLine()
End Sub
End Module
' The example displays the following output:
' 'a' occurs at the following character positions: 4, 7, 15
'
' An exception (ArgumentNullException) occurred.
' Message:
' Value cannot be null.
' Parameter name: value
'
' Stack Trace:
' at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
' ngComparison comparisonType)
' at Library.FindOccurrences(String s, String f)
' at Example.Main()
반면, 다음 문을 사용하여 예외가 다시 throw되는 경우:
throw e;
Throw e
raise e
... 그런 다음 전체 호출 스택이 유지되지 않고 예제에서 다음 출력을 생성합니다.
'a' occurs at the following character positions: 4, 7, 15
An exception (ArgumentNullException) occurred.
Message:
Value cannot be null.
Parameter name: value
Stack Trace:
at Library.FindOccurrences(String s, String f)
at Example.Main()
약간 더 번거로운 대안은 새 예외를 throw하고 내부 예외에서 원래 예외의 호출 스택 정보를 유지하는 것입니다. 그런 다음 호출자는 새 예외의 InnerException 속성을 사용하여 스택 프레임 및 원래 예외에 대한 기타 정보를 검색할 수 있습니다. 이 경우 throw 문은 다음과 같습니다.
throw new ArgumentNullException("You must supply a search string.", e);
raise (ArgumentNullException("You must supply a search string.", e) )
Throw New ArgumentNullException("You must supply a search string.",
e)
예외를 처리하는 사용자 코드는 다음 예외 처리기에서 보여 주듯이 속성에 원래 예외에 대한 정보가 포함되어 있음을 InnerException 알아야 합니다.
try
{
indexes = s.FindOccurrences(toFind);
ShowOccurrences(s, toFind, indexes);
}
catch (ArgumentNullException e)
{
Console.WriteLine("An exception ({0}) occurred.",
e.GetType().Name);
Console.WriteLine(" Message:\n{0}", e.Message);
Console.WriteLine(" Stack Trace:\n {0}", e.StackTrace);
Exception ie = e.InnerException;
if (ie != null)
{
Console.WriteLine(" The Inner Exception:");
Console.WriteLine(" Exception Name: {0}", ie.GetType().Name);
Console.WriteLine(" Message: {0}\n", ie.Message);
Console.WriteLine(" Stack Trace:\n {0}\n", ie.StackTrace);
}
}
// The example displays the following output:
// 'a' occurs at the following character positions: 4, 7, 15
//
// An exception (ArgumentNullException) occurred.
// Message: You must supply a search string.
//
// Stack Trace:
// at Library.FindOccurrences(String s, String f)
// at Example.Main()
//
// The Inner Exception:
// Exception Name: ArgumentNullException
// Message: Value cannot be null.
// Parameter name: value
//
// Stack Trace:
// at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
// ngComparison comparisonType)
// at Library.FindOccurrences(String s, String f)
try
let indexes = findOccurrences s toFind
showOccurrences toFind indexes
with :? ArgumentNullException as e ->
printfn $"An exception ({e.GetType().Name}) occurred."
printfn $" Message:\n{e.Message}"
printfn $" Stack Trace:\n {e.StackTrace}"
let ie = e.InnerException
if ie <> null then
printfn " The Inner Exception:"
printfn $" Exception Name: {ie.GetType().Name}"
printfn $" Message: {ie.Message}\n"
printfn $" Stack Trace:\n {ie.StackTrace}\n"
// The example displays the following output:
// 'a' occurs at the following character positions: 4, 7, 15
//
// An exception (ArgumentNullException) occurred.
// Message: You must supply a search string.
//
// Stack Trace:
// at Library.FindOccurrences(String s, String f)
// at Example.Main()
//
// The Inner Exception:
// Exception Name: ArgumentNullException
// Message: Value cannot be null.
// Parameter name: value
//
// Stack Trace:
// at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
// ngComparison comparisonType)
// at Library.FindOccurrences(String s, String f)
Try
indexes = s.FindOccurrences(toFind)
ShowOccurrences(s, toFind, indexes)
Catch e As ArgumentNullException
Console.WriteLine("An exception ({0}) occurred.",
e.GetType().Name)
Console.WriteLine(" Message: {1}{0}", vbCrLf, e.Message)
Console.WriteLine(" Stack Trace:{0} {1}{0}", vbCrLf, e.StackTrace)
Dim ie As Exception = e.InnerException
If ie IsNot Nothing Then
Console.WriteLine(" The Inner Exception:")
Console.WriteLine(" Exception Name: {0}", ie.GetType().Name)
Console.WriteLine(" Message: {1}{0}", vbCrLf, ie.Message)
Console.WriteLine(" Stack Trace:{0} {1}{0}", vbCrLf, ie.StackTrace)
End If
End Try
' The example displays the following output:
' 'a' occurs at the following character positions: 4, 7, 15
'
' An exception (ArgumentNullException) occurred.
' Message: You must supply a search string.
'
' Stack Trace:
' at Library.FindOccurrences(String s, String f)
' at Example.Main()
'
' The Inner Exception:
' Exception Name: ArgumentNullException
' Message: Value cannot be null.
' Parameter name: value
'
' Stack Trace:
' at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
' ngComparison comparisonType)
' at Library.FindOccurrences(String s, String f)
표준 예외 선택
예외를 throw해야 하는 경우 사용자 지정 예외를 구현하는 대신 .NET에서 기존 예외 형식을 사용할 수 있습니다. 다음 두 가지 조건에서 표준 예외 형식을 사용해야 합니다.
사용 오류(즉, 메서드를 호출하는 개발자가 만든 프로그램 논리의 오류)로 인해 발생하는 예외를 throw합니다. 일반적으로 , ArgumentNullException, InvalidOperationException또는 NotSupportedException.와 같은 ArgumentException예외를 throw합니다. 예외 개체를 인스턴스화할 때 예외 개체의 생성자에 제공하는 문자열은 개발자가 오류를 수정할 수 있도록 오류를 설명해야 합니다. 자세한 내용은 Message 속성을 참조하세요.
기존 .NET 예외를 사용하여 호출자에게 전달할 수 있는 오류를 처리하고 있습니다. 가능한 가장 파생된 예외를 throw해야 합니다. 예를 들어 메서드에 인수가 열거형 형식의 유효한 멤버여야 하는 경우 인수가 아닌 ArgumentException(가장 파생된 클래스)를 throw InvalidEnumArgumentException 해야 합니다.
다음 표에서는 일반적인 예외 유형 및 예외를 throw할 조건을 나열합니다.
예외 | 조건 |
---|---|
ArgumentException | 메서드에 전달되는 null이 아닌 인수가 잘못되었습니다. |
ArgumentNullException | 메서드에 전달되는 인수는 .입니다 null . |
ArgumentOutOfRangeException | 인수가 유효한 값 범위를 벗어났습니다. |
DirectoryNotFoundException | 디렉터리 경로의 일부가 잘못되었습니다. |
DivideByZeroException | 정수 또는 Decimal 나누기 작업의 분모는 0입니다. |
DriveNotFoundException | 드라이브를 사용할 수 없거나 존재하지 않습니다. |
FileNotFoundException | 파일이 없습니다. |
FormatException | 값은 다음과 같은 Parse 변환 메서드에 의해 문자열에서 변환할 적절한 형식이 아닙니다. |
IndexOutOfRangeException | 인덱스가 배열 또는 컬렉션의 범위를 벗어났습니다. |
InvalidOperationException | 개체의 현재 상태에서 메서드 호출이 잘못되었습니다. |
KeyNotFoundException | 컬렉션의 멤버에 액세스하기 위해 지정된 키를 찾을 수 없습니다. |
NotImplementedException | 메서드 또는 작업이 구현되지 않습니다. |
NotSupportedException | 메서드 또는 작업은 지원되지 않습니다. |
ObjectDisposedException | 삭제된 개체에 대해 작업이 수행됩니다. |
OverflowException | 산술, 캐스팅 또는 변환 연산으로 인해 오버플로가 발생합니다. |
PathTooLongException | 경로 또는 파일 이름이 시스템 정의 최대 길이를 초과합니다. |
PlatformNotSupportedException | 현재 플랫폼에서는 작업이 지원되지 않습니다. |
RankException | 잘못된 차원 수를 가진 배열이 메서드에 전달됩니다. |
TimeoutException | 작업에 할당된 시간 간격이 만료되었습니다. |
UriFormatException | 잘못된 URI(Uniform Resource Identifier)가 사용됩니다. |
사용자 지정 예외 구현
다음 경우 기존 .NET 예외를 사용하여 오류 조건을 처리하는 것은 적절하지 않습니다.
예외가 기존 .NET 예외에 매핑할 수 없는 고유한 프로그램 오류를 반영하는 경우
예외에 기존 .NET 예외에 적합한 처리와 다른 처리가 필요하거나 유사한 예외에서 예외를 명확하게 구분해야 하는 경우 예를 들어 대상 정수 형식 범위를 벗어난 문자열의 숫자 표현을 구문 분석할 때 예외를 throw ArgumentOutOfRangeException 하는 경우 호출자가 메서드를 호출할 때 적절한 제한된 값을 제공하지 않는 오류에 대해 동일한 예외를 사용하지 않으려는 것입니다.
Exception 클래스는 .NET에서 모든 예외의 기본 클래스입니다. 많은 파생 클래스는 클래스 멤버의 Exception 상속된 동작을 사용하며 멤버를 재정의 Exception하지 않으며 고유한 멤버를 정의하지도 않습니다.
고유한 예외 클래스를 정의하려면 다음을 수행합니다.
에서 Exception상속되는 클래스를 정의합니다. 필요한 경우 예외에 대한 추가 정보를 제공하기 위해 클래스에 필요한 고유 멤버를 정의합니다. 예를 들어 ArgumentException 클래스에는 ParamName 인수로 인해 예외가 발생한 매개 변수의 이름을 지정하는 속성이 포함되며 RegexMatchTimeoutException , 이 속성에는 제한 시간 간격을 MatchTimeout 나타내는 속성이 포함됩니다.
필요한 경우 기능을 변경하거나 수정하려는 상속된 멤버를 재정의합니다. 대부분의 기존 파생 클래스는 Exception 상속된 멤버의 동작을 재정의하지 않습니다.
사용자 지정 예외 개체를 직렬화할 수 있는지 여부를 확인합니다. Serialization을 사용하면 예외에 대한 정보를 저장할 수 있으며 원격 컨텍스트에서 서버 및 클라이언트 프록시에서 예외 정보를 공유할 수 있습니다. 예외 개체를 직렬화할 수 있도록 하려면 특성으로 SerializableAttribute 표시합니다.
예외 클래스의 생성자를 정의합니다. 일반적으로 예외 클래스에는 다음 생성자 중 하나 이상이 있습니다.
Exception()- 기본값을 사용하여 새 예외 개체의 속성을 초기화합니다.
Exception(String)지정된 오류 메시지를 사용하여 새 예외 개체를 초기화하는 입니다.
Exception(String, Exception)지정된 오류 메시지 및 내부 예외를 사용하여 새 예외 개체를 초기화하는 입니다.
Exception(SerializationInfo, StreamingContext)
protected
serialize된 데이터에서 새 예외 개체를 초기화하는 생성자입니다. 예외 개체를 직렬화할 수 있도록 선택한 경우 이 생성자를 구현해야 합니다.
다음 예제에서는 사용자 지정 예외 클래스의 사용을 보여 줍니다. 소수가 아닌 시작 번호를 지정하여 클라이언트가 소수 시퀀스를 검색하려고 할 때 throw되는 예외를 정의 NotPrimeException
합니다. 예외는 예외를 발생시킨 소수가 아닌 숫자를 반환하는 새 속성을 NonPrime
정의합니다. 클래스는 보호된 매개 변수가 없는 생성자와 serialization NotPrimeException
을 위한 매개 변수 및 StreamingContextSerializationInfo 매개 변수를 구현하는 것 외에도 속성을 지원하는 NonPrime
세 개의 추가 생성자를 정의합니다. 각 생성자는 소수가 아닌 값의 값을 유지하는 것 외에도 기본 클래스 생성자를 호출합니다. NotPrimeException
또한 클래스는 특성으로 SerializableAttribute 표시됩니다.
using System;
using System.Runtime.Serialization;
[Serializable()]
public class NotPrimeException : Exception
{
private int notAPrime;
protected NotPrimeException()
: base()
{ }
public NotPrimeException(int value) :
base(String.Format("{0} is not a prime number.", value))
{
notAPrime = value;
}
public NotPrimeException(int value, string message)
: base(message)
{
notAPrime = value;
}
public NotPrimeException(int value, string message, Exception innerException) :
base(message, innerException)
{
notAPrime = value;
}
protected NotPrimeException(SerializationInfo info,
StreamingContext context)
: base(info, context)
{ }
public int NonPrime
{ get { return notAPrime; } }
}
namespace global
open System
open System.Runtime.Serialization
[<Serializable>]
type NotPrimeException =
inherit Exception
val notAPrime: int
member this.NonPrime =
this.notAPrime
new (value) =
{ inherit Exception($"%i{value} is not a prime number."); notAPrime = value }
new (value, message) =
{ inherit Exception(message); notAPrime = value }
new (value, message, innerException: Exception) =
{ inherit Exception(message, innerException); notAPrime = value }
// F# does not support protected members
new () =
{ inherit Exception(); notAPrime = 0 }
new (info: SerializationInfo, context: StreamingContext) =
{ inherit Exception(info, context); notAPrime = 0 }
Imports System.Runtime.Serialization
<Serializable()> _
Public Class NotPrimeException : Inherits Exception
Private notAPrime As Integer
Protected Sub New()
MyBase.New()
End Sub
Public Sub New(value As Integer)
MyBase.New(String.Format("{0} is not a prime number.", value))
notAPrime = value
End Sub
Public Sub New(value As Integer, message As String)
MyBase.New(message)
notAPrime = value
End Sub
Public Sub New(value As Integer, message As String, innerException As Exception)
MyBase.New(message, innerException)
notAPrime = value
End Sub
Protected Sub New(info As SerializationInfo,
context As StreamingContext)
MyBase.New(info, context)
End Sub
Public ReadOnly Property NonPrime As Integer
Get
Return notAPrime
End Get
End Property
End Class
다음 예제에 표시된 클래스는 PrimeNumberGenerator
Eratosthenes의 Sieve를 사용하여 소수 시퀀스를 2에서 해당 클래스 생성자에 대한 호출에서 클라이언트가 지정한 제한으로 계산합니다. 이 메서드는 GetPrimesFrom
지정된 하한보다 크거나 같은 소수를 모두 반환하지만 하위 제한이 소수가 아닌 경우 throw합니다 NotPrimeException
.
using System;
using System.Collections.Generic;
[Serializable]
public class PrimeNumberGenerator
{
private const int START = 2;
private int maxUpperBound = 10000000;
private int upperBound;
private bool[] primeTable;
private List<int> primes = new List<int>();
public PrimeNumberGenerator(int upperBound)
{
if (upperBound > maxUpperBound)
{
string message = String.Format(
"{0} exceeds the maximum upper bound of {1}.",
upperBound, maxUpperBound);
throw new ArgumentOutOfRangeException(message);
}
this.upperBound = upperBound;
// Create array and mark 0, 1 as not prime (True).
primeTable = new bool[upperBound + 1];
primeTable[0] = true;
primeTable[1] = true;
// Use Sieve of Eratosthenes to determine prime numbers.
for (int ctr = START; ctr <= (int)Math.Ceiling(Math.Sqrt(upperBound));
ctr++)
{
if (primeTable[ctr]) continue;
for (int multiplier = ctr; multiplier <= upperBound / ctr; multiplier++)
if (ctr * multiplier <= upperBound) primeTable[ctr * multiplier] = true;
}
// Populate array with prime number information.
int index = START;
while (index != -1)
{
index = Array.FindIndex(primeTable, index, (flag) => !flag);
if (index >= 1)
{
primes.Add(index);
index++;
}
}
}
public int[] GetAllPrimes()
{
return primes.ToArray();
}
public int[] GetPrimesFrom(int prime)
{
int start = primes.FindIndex((value) => value == prime);
if (start < 0)
throw new NotPrimeException(prime, String.Format("{0} is not a prime number.", prime));
else
return primes.FindAll((value) => value >= prime).ToArray();
}
}
namespace global
open System
[<Serializable>]
type PrimeNumberGenerator(upperBound) =
let start = 2
let maxUpperBound = 10000000
let primes = ResizeArray()
let primeTable =
upperBound + 1
|> Array.zeroCreate<bool>
do
if upperBound > maxUpperBound then
let message = $"{upperBound} exceeds the maximum upper bound of {maxUpperBound}."
raise (ArgumentOutOfRangeException message)
// Create array and mark 0, 1 as not prime (True).
primeTable[0] <- true
primeTable[1] <- true
// Use Sieve of Eratosthenes to determine prime numbers.
for i = start to float upperBound |> sqrt |> ceil |> int do
if not primeTable[i] then
for multiplier = i to upperBound / i do
if i * multiplier <= upperBound then
primeTable[i * multiplier] <- true
// Populate array with prime number information.
let mutable index = start
while index <> -1 do
index <- Array.FindIndex(primeTable, index, fun flag -> not flag)
if index >= 1 then
primes.Add index
index <- index + 1
member _.GetAllPrimes() =
primes.ToArray()
member _.GetPrimesFrom(prime) =
let start =
Seq.findIndex ((=) prime) primes
if start < 0 then
raise (NotPrimeException(prime, $"{prime} is not a prime number.") )
else
Seq.filter ((>=) prime) primes
|> Seq.toArray
Imports System.Collections.Generic
<Serializable()> Public Class PrimeNumberGenerator
Private Const START As Integer = 2
Private maxUpperBound As Integer = 10000000
Private upperBound As Integer
Private primeTable() As Boolean
Private primes As New List(Of Integer)
Public Sub New(upperBound As Integer)
If upperBound > maxUpperBound Then
Dim message As String = String.Format(
"{0} exceeds the maximum upper bound of {1}.",
upperBound, maxUpperBound)
Throw New ArgumentOutOfRangeException(message)
End If
Me.upperBound = upperBound
' Create array and mark 0, 1 as not prime (True).
ReDim primeTable(upperBound)
primeTable(0) = True
primeTable(1) = True
' Use Sieve of Eratosthenes to determine prime numbers.
For ctr As Integer = START To CInt(Math.Ceiling(Math.Sqrt(upperBound)))
If primeTable(ctr) Then Continue For
For multiplier As Integer = ctr To CInt(upperBound \ ctr)
If ctr * multiplier <= upperBound Then primeTable(ctr * multiplier) = True
Next
Next
' Populate array with prime number information.
Dim index As Integer = START
Do While index <> -1
index = Array.FindIndex(primeTable, index, Function(flag)
Return Not flag
End Function)
If index >= 1 Then
primes.Add(index)
index += 1
End If
Loop
End Sub
Public Function GetAllPrimes() As Integer()
Return primes.ToArray()
End Function
Public Function GetPrimesFrom(prime As Integer) As Integer()
Dim start As Integer = primes.FindIndex(Function(value)
Return value = prime
End Function)
If start < 0 Then
Throw New NotPrimeException(prime, String.Format("{0} is not a prime number.", prime))
Else
Return primes.FindAll(Function(value)
Return value >= prime
End Function).ToArray()
End If
End Function
End Class
두 번 호출 하는 다음 예제는 GetPrimesFrom
메서드 사용 하 여 소수가 아닌 숫자를 애플리케이션 도메인 경계를 교차 하는 중입니다. 두 경우 모두 예외가 throw되고 클라이언트 코드에서 성공적으로 처리됩니다.
using System;
using System.Reflection;
class Example1
{
public static void Main()
{
int limit = 10000000;
PrimeNumberGenerator primes = new PrimeNumberGenerator(limit);
int start = 1000001;
try
{
int[] values = primes.GetPrimesFrom(start);
Console.WriteLine("There are {0} prime numbers from {1} to {2}",
start, limit);
}
catch (NotPrimeException e)
{
Console.WriteLine("{0} is not prime", e.NonPrime);
Console.WriteLine(e);
Console.WriteLine("--------");
}
AppDomain domain = AppDomain.CreateDomain("Domain2");
PrimeNumberGenerator gen = (PrimeNumberGenerator)domain.CreateInstanceAndUnwrap(
typeof(Example).Assembly.FullName,
"PrimeNumberGenerator", true,
BindingFlags.Default, null,
new object[] { 1000000 }, null, null);
try
{
start = 100;
Console.WriteLine(gen.GetPrimesFrom(start));
}
catch (NotPrimeException e)
{
Console.WriteLine("{0} is not prime", e.NonPrime);
Console.WriteLine(e);
Console.WriteLine("--------");
}
}
}
open System
open System.Reflection
let limit = 10000000
let primes = PrimeNumberGenerator limit
let start = 1000001
try
let values = primes.GetPrimesFrom start
printfn $"There are {values.Length} prime numbers from {start} to {limit}"
with :? NotPrimeException as e ->
printfn $"{e.NonPrime} is not prime"
printfn $"{e}"
printfn "--------"
let domain = AppDomain.CreateDomain "Domain2"
let gen =
domain.CreateInstanceAndUnwrap(
typeof<PrimeNumberGenerator>.Assembly.FullName,
"PrimeNumberGenerator", true,
BindingFlags.Default, null,
[| box 1000000 |], null, null)
:?> PrimeNumberGenerator
try
let start = 100
printfn $"{gen.GetPrimesFrom start}"
with :? NotPrimeException as e ->
printfn $"{e.NonPrime} is not prime"
printfn $"{e}"
printfn "--------"
Imports System.Reflection
Module Example
Sub Main()
Dim limit As Integer = 10000000
Dim primes As New PrimeNumberGenerator(limit)
Dim start As Integer = 1000001
Try
Dim values() As Integer = primes.GetPrimesFrom(start)
Console.WriteLine("There are {0} prime numbers from {1} to {2}",
start, limit)
Catch e As NotPrimeException
Console.WriteLine("{0} is not prime", e.NonPrime)
Console.WriteLine(e)
Console.WriteLine("--------")
End Try
Dim domain As AppDomain = AppDomain.CreateDomain("Domain2")
Dim gen As PrimeNumberGenerator = domain.CreateInstanceAndUnwrap(
GetType(Example).Assembly.FullName,
"PrimeNumberGenerator", True,
BindingFlags.Default, Nothing,
{1000000}, Nothing, Nothing)
Try
start = 100
Console.WriteLine(gen.GetPrimesFrom(start))
Catch e As NotPrimeException
Console.WriteLine("{0} is not prime", e.NonPrime)
Console.WriteLine(e)
Console.WriteLine("--------")
End Try
End Sub
End Module
' The example displays the following output:
' 1000001 is not prime
' NotPrimeException: 1000001 is not a prime number.
' at PrimeNumberGenerator.GetPrimesFrom(Int32 prime)
' at Example.Main()
' --------
' 100 is not prime
' NotPrimeException: 100 is not a prime number.
' at PrimeNumberGenerator.GetPrimesFrom(Int32 prime)
' at Example.Main()
' --------
예제
다음 예제에서는 오류를 처리 ArithmeticException 하도록 정의된 (with
F#) 블록을 보여 catch
줍니다. 이 catch
블록은 오류에서 ArithmeticException 파생되고 오류에 대해 DivideByZeroException 명시적으로 정의된 블록이 없기 catch
때문에 DivideByZeroException 오류를 catch DivideByZeroException 합니다.
using System;
class ExceptionTestClass
{
public static void Main()
{
int x = 0;
try
{
int y = 100 / x;
}
catch (ArithmeticException e)
{
Console.WriteLine($"ArithmeticException Handler: {e}");
}
catch (Exception e)
{
Console.WriteLine($"Generic Exception Handler: {e}");
}
}
}
/*
This code example produces the following results:
ArithmeticException Handler: System.DivideByZeroException: Attempted to divide by zero.
at ExceptionTestClass.Main()
*/
module ExceptionTestModule
open System
let x = 0
try
let y = 100 / x
()
with
| :? ArithmeticException as e ->
printfn $"ArithmeticException Handler: {e}"
| e ->
printfn $"Generic Exception Handler: {e}"
// This code example produces the following results:
// ArithmeticException Handler: System.DivideByZeroException: Attempted to divide by zero.
// at <StartupCode$fs>.$ExceptionTestModule.main@()
Class ExceptionTestClass
Public Shared Sub Main()
Dim x As Integer = 0
Try
Dim y As Integer = 100 / x
Catch e As ArithmeticException
Console.WriteLine("ArithmeticException Handler: {0}", e.ToString())
Catch e As Exception
Console.WriteLine("Generic Exception Handler: {0}", e.ToString())
End Try
End Sub
End Class
'
'This code example produces the following results:
'
'ArithmeticException Handler: System.OverflowException: Arithmetic operation resulted in an overflow.
' at ExceptionTestClass.Main()
'
.NET