본문 바로가기

취미로 하는 게임코딩_gameCodingAsHobby/유니티unity로 게임 만들기

유니티39_C#_24_Exception handling 예외 처리

예외(Exception)

 

컴퓨터에서 일어나는 에러는 2가지가 있다.

 

첫째는 코드를 작성할 때 발생하는 컴파일 에러(compile error)

둘째는 프로그램 실행 중에 발생하는 런타임 에러(run-time error)

 

첫째 경우는 코드를 입력하는 사람이 잘못 입력하면 편집기 등에서 문제가 있는 부분을 대부분 알려주므로 어디가 잘못인지 파악하는 것이 어렵지는 않다.

 

둘째 경우는 프로그램을 실행(run)할 때 생기는 런타임 에러인데 이 경우도 컴퓨터가 예상하지 못한 에러와 프로그램 내에서 예상할 수 있는 에러로 나눌 수 있다.

 

런타임 중 프로그램 내에서 일어나는 예상할 수 있는 에러를 예외(Exception)이라고 한다.

C#에는 이런 Exception(예외)이 발생하면 프로그램을 멈추고 그것을 처리하는 체계를 가지고 있다.

 

C#에는 예외에 대해서는 System.Exception  클래스에 정의하고 있는데 다양한 예외들 중 대표적인 것은 다음과 같다.

 

  • 배열에서 인덱스에 없는 것을 참조할 때 발생시키는 IndexOutOfRangeException
  • 입출력 에러가 났을 때 발생시키는 IOException
  • null객체를 참조하면 발생시키는 NullReferenceException
  • 0 으로 나누는 시도가 있을 때 발생시키는 DivideByZeroException
  • 메모리가 부족할 때 발생시키는 OutOfMemoryException
  • 타입 캐스팅에서 발생하는 에러가 있을 때 발생시키는 InvalidCastException
  • 배열 타입이 맞지 않을 때 발생시키는 ArrayTypeMismatchException
  • Stack(스택) 영역의 메모리가 지정된 범위를 초과할 때 발생시키는 StackOverflowException

 

예제1

 

Exception이 발생하도록 코드를 작성해서 실제로 어떻게 나타나는 지 확인해보자.

 

 

위와 같은 스크립트를 만든다.

배열(Array)을 만들고 for반복문으로 배열 값을 모두 더해서 합(sum)을 계산하는 코드이다.

그런데 배열의 요소(element) 수는 3 이고, index(인덱스) 번호는 0, 1, 2 인데 for 반복문 조건에서 인덱스 번호를 0, 1, 2, 3 으로 잘못 설정했다.

 

유니티로 출력하면 다음과 같은 예외를 발생시킨다.

 

IndexOutOfRangeException : Index was outside the bounds of the array.

인덱스 범위 초과 예외 : 인덱스는 배열의 경계 바깥에 있었다.

 

그래서 이런 Exception이 발생했을 때, 어떤 식으로 처리하라는 조치를 미리 만들어 두는 방법들이 있다.

 

try-catch-finally

*try : 시도하다

*catch : 잡다

*finally : 마지막으로, 최종적으로

 

위의 코드와 같이 예외가 생길 수 있는 경우에 try, catch, finally 키워드를 사용해서 예외를 처리할 수 있다.

 

  1. try는 예외가 발생할 가능성이 있는 코드를 묶는다. (캡슐화)
  2. catch는 예외가 발생할 경우 그것을 잡는다. 그리고 그것을 어떻게 처리할 것인지 적어놓는다. 여러 가지 예외가 발생할 가능성이 있다면 catch블록을 여러 개 만들어 각 상황별로 다르게 처리하도록 만들 수 있다.
  3. finally는 예외가 생기든, 안 생기든 상관없이 무조건 실행할 코드를 적는다. 그러므로 이 부분을 생략할 수도 있다.

 

 

10번 줄에 예외가 생길 가능성이 있는 for반복문을 try와 함께 중괄호로 묶는다.

17번 줄에 catch 로 예외를 잡아낸다. 괄호에는 System.Exception클래스에 있는 예외 타입과 그것을 저장할 변수를 하나 적는다. 여기서는 exception으로 했다. 이 변수명은 보통 첫글자만 따서 e 로 표시하기도 한다. 

19번 줄에 예외가 발생했을 때 처리할 내용을 적는다.

여기서는 IndexOutofRangeException클래스에 있는 Message(메세지) 프라퍼티에 정의된 내용을 출력한다.

21번 줄에 예외 발생과 상관없이 실행할 내용을 작성한다.

여기서는 예외가 발생하든, 안하든 sum 값을 출력한다.

 

스크립트를 저장한 후 실행하면 다음과 같이 출력될 것이다.

 

첫째는 예외가 발생했으므로 IndexOutofRangeException클래스에서 전달받은 Message가 출력된다.

둘째는 어쨌든 finally에서 14번 코드를 실행한 결과 sum 값 6을 출력한다.

 

 

예제2

 

예를 하나 더 만들어 본다.

 

 

13번 줄에 DivideNumber라는 클래스를 만들었다.

*divide : 나누다

15번 줄에 필드 result 를 만든다.

*result : 결과

17번 줄에 생성자를 만든다. 생성자에서 필드를 0으로 초기화한다.

22번 줄에 Division이라는 메서드를 만든다. 매개변수 2개를 가진다.

이 메서드가 호출되면 첫째 매개변수를 둘째 매개변수로 나누어서 필드result에 저장한다.

*division : 나누기, 분할

 

7번 줄에 클래스 객체를 만들어서 변수 test에 넣는다.

8번 줄에 Division메서드에 인수를 전달한다.

9번 줄에 result값을 콘솔 창에 출력한다.

 

실행하면 위와 같이 result값 1이 나올 것이다.

 

그런데 위 코드에서는 8번 줄에서 Division메서드에 인수를 전달할 때 (5, 0) 처럼 0을 입력해서 전달할 가능성이 있다.

 

위와 같이 인수를 전달하면 아래와 같이 에러가 발생한다.

 

DivideByZeroException : Attempted to divide by zero.

( 0으로 나누기 예외 : 0으로 나누려고 시도함 )

 

연산에서 0으로 나누기(divide by 0)는 정의되어 있지 않기 때문에 이런 상황이 생기면 위와 같이 Exception(예외)을 발생시킨다.

 

이런 경우는 예외가 일어날 가능성을 미리 예측할 수 있기 때문에 try-catch-finally로 미리 예외 발생 시 어떻게 처리할 것인지 잘 대처하도록 준비해 둘 수 있다.  

 

try-catch-finally를 사용해서 예외 처리를 해보자.

 

먼저 Exception은 네임스페이스 System에 있기 때문에 예외 클래스를 사용하기 위해 using System;을 추가한다.

 

만약 using System을 사용하지 않으려면 앞에서 System.IndexOutOfRangeException과 같이 'System.예외타입' 형태를 사용하면 된다. 여기서는 using키워드를 사용한다.

 

예외가 일어날 가능성이 있는 코드가 27번 줄이므로 try { } 로 감싸준다.

30번 줄에서 catch( )로 '예외 타입'을 적고 예외에서 전달받는 내용을 저장할 변수로 exception을 만든다. 

32번 줄에서 해당 예외가 일어나면 변수 exception 내용을 콘솔창에 출력하도록 한다.

34번 줄에서 finally{ } 로 예외가 일어나든, 일어나지 않든 간에 실행할 내용을 적는다.

여기서는 result값을 출력하도록 한다.

 

위와 같이 예외 처리를 한 후 Division메서드 인수로 5와 0을 입력해서 실행해보자.

 

예외가 발생하여 DivideByZeroException클래스에서 전달 받은 내용이 출력되고 결과에는 result 초기값 0 이 출력된다.

마지막에 나타나는 0은 Debug.Log(test.result) 값이다.

 

아래와 같이 예외가 발생하지 않는 경우는 finally에서 작성한 내용만 출력한다.

 

끝.

Wraven...