예외 처리

예외 처리는 프로그램이 갑작스럽게 종료 되거나 멈추는 상황을 예방하고 안정적으로 유지할 수 있도록 구현해준다.

 

예외 처리 구현

try에 예외가 발생할 수 있는 코드를 작성하고 catch에 예외 처리를 한다.

catch문은 위에서부터 순서대로 실행된다. 다중으로 붙일 수 있어 여러 가지 예외 처리를 할 수 있고, 예외 객체를 받아올 수 있어 예외 처리에 발생한 여러 정보들을 표시할 수 있다.

마지막으로 finally은 예외와 상관 없이 무조건 실행되는 코드이다. 필요하지 않다면 생략 가능하다.

try
{
    // 예외가 발생할 수 있는 코드
}
catch (ExceptionType1 ex)
{
    // ExceptionType1에 해당하는 예외 처리
}
catch (ExceptionType2 ex)
{
    // ExceptionType2에 해당하는 예외 처리
}
finally
{
    // 예외 발생 여부와 상관없이 항상 실행되는 코드
}

 

사용자 정의 예외

사용자가 필요에 따라 자신만의 예외 클래스를 작성할 수 있다.

Exception 클래스를 상속받아 작성한다.

public class NegativeNumberException : Exception
{
    public NegativeNumberException(string message) : base(message)
    {
    }
}
internal class Program
    {
    static void Main(string[] args)
    {
        try
        {
            int number = -10;
            if (number < 0)
            {
                throw new NegativeNumberException("음수는 처리할 수 없습니다.");
            }
        }
        catch (NegativeNumberException ex)
        {
            Console.WriteLine(ex.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine("예외가 발생했습니다: " + ex.Message);
        }
    }
}

 

예외 처리 할 때는 가능한 구체적인 예외 클래스를 사용하는 것이 코드가 안정적이고 예외 처리에 대한 처리가 더욱 정확해진다.

if else문으로 예외를 처리하면 되지 않나 생각이 들었었는데 이 때문에 예외 처리를 사용한다는 것을 깨달았다.

 

 

값형과 참조형

값형(Value Type)

변수에 값을 직접 저장한다. 변수가 독립적으로 데이터를 가지며 어딘가에 할당하거나 대입 해야할 때 값을 복사해서 준다.

예) int, float, double, bool 등

struct MyStruct
{
    public int Value;
}

MyStruct struct1 = new MyStruct();
struct1.Value = 10;

MyStruct struct2 = struct1; // struct2는 struct1의 값 복사

struct2.Value = 20;

Console.WriteLine(struct1.Value); // 출력 결과: 10

 

 

참조형(Reference Type)

변수에 데이터에 대한 참조(메모리 주소)를 저장한다. 변수가 동일한 데이터를 참조하여 할당하거나 대입 해야할 때 참조를 복사해서 준다.

예) 클래스, 배열, 인터페이스 등

class MyClass
{
    public int Value;
}

MyClass obj1 = new MyClass();
obj1.Value = 10;

MyClass obj2 = obj1; // obj2는 obj1과 동일한 객체를 참조

obj2.Value = 20;

Console.WriteLine(obj1.Value); // 출력 결과: 20

 

 

박싱과 언박싱

박싱은 값형을 참조형으로 변환한다. 언박싱은 박싱으로 참조형이었던 값형을 다시 값형으로 돌려놓는다.

 

object 형식은 직,간접적으로 모든 클래스의 최상위 클래스이다.

// 값형
int x = 10;
int y = x;
y = 20;
Console.WriteLine("x: " + x); // 출력 결과: 10
Console.WriteLine("y: " + y); // 출력 결과: 20

// 참조형
int[] arr1 = new int[] { 1, 2, 3 };
int[] arr2 = arr1;
arr2[0] = 4;
Console.WriteLine("arr1[0]: " + arr1[0]); // 출력 결과: 4
Console.WriteLine("arr2[0]: " + arr2[0]); // 출력 결과: 4

// 박싱과 언박싱
int num1 = 10;
object obj = num1; // 박싱
int num2 = (int)obj; // 언박싱
Console.WriteLine("num1: " + num1); // 출력 결과: 10
Console.WriteLine("num2: " + num2); // 출력 결과: 10
List<object> myList = new List<object>();

// 박싱: 값 형식을 참조 형식으로 변환하여 리스트에 추가
int intValue = 10;
myList.Add(intValue); // int를 object로 박싱하여 추가

float floatValue = 3.14f;
myList.Add(floatValue); // float를 object로 박싱하여 추가

// 언박싱: 참조 형식을 값 형식으로 변환하여 사용
int value1 = (int)myList[0]; // object를 int로 언박싱
float value2 = (float)myList[1]; // object를 float로 언박싱

값형을 참조형으로 변환할 때, 값형이 사라지는 것이 아니라 남아있고 값형에 대한 참조형으로 변환되어 새롭게 받아지는 것이다. 그렇기 때문에 너무 많은 박싱과 언박싱이 일어나면 성능이 저하된다.

 

값과 참조형, 박싱과 언박싱은 자주 사용되기 때문에 잘 알아두는 것이 좋을 것 같다.

+ Recent posts