TIL

예외처리 값형&참조형 박싱&언박싱

박민혁_kog 2023. 8. 16. 20:24

예외 처리  - 디버깅 비슷한것

예외 : 프로그램 실행 중 발생한 예기치 않은 상황

  • 예외 처리의 필요성과 장점
    • 예외 처리는 예외 상황에 대비하여 프로그램을 안정적으로 유지하는 데 도움을 줍니다.
    • 예외 처리를 통해 오류 상황을 적절히 처리하고, 프로그램의 실행을 계속할 수 있습니다.
    • 예외 처리는 프로그램의 안정성을 높이고 디버깅을 용이하게 합니다.
  • 예외 처리 구현
    • C#에서는 try-catch 블록을 사용하며  try 블록 내에서 예외가 발생할 수 있는 코드를 작성하고, catch 블록에서 예외를 처리합니다.

finally 블록

  • finally 블록은 예외 발생 여부와 상관없이 항상 실행되는 코드 블록입니다.

 

사용자 정의 예외 클래스 작성

  • 사용자는 필요에 따라 자신만의 예외 클래스를 작성할 수 있습니다.
  • 사용자 정의 예외 클래스는 Exception 클래스를 상속받아 작성하며, 추가적인 기능이나 정보를 제공할 수 있습니다.
public class oneCatch : Exception   //사용자 정의 
{
    public NegativeNumberException(string message) : base(message)
    {
    }
}

public class twoCatch : Exception
{
    public NegativeNumberException(string message) : base(message)
    {
    }
}

try
{
    // 예외가 발생할 수 있는 코드
    int number = 10;
    if (number < 0)
    {
        throw new oneCatch("1번 캐치 작동");
    }
    else
    {
    	throw new twoCatch("2번 캐치 작동");
    }
}
catch (oneCatch ex)
{
    // ExceptionType1에 해당하는 예외 처리
}
catch (twoCatch ex)
{
    // ExceptionType2에 해당하는 예외 처리
}
finally
{
    // 예외 발생 여부와 상관없이 항상 실행되는 코드
}

 

 

값형(Value Type)

  • 값형은 변수에 값을 직접 저장합니다.
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 구조체2는 밸류1을 복사하고 값을 변경했으나
여전히 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

Boxing / Unboxing (박싱 / 언박싱)

오브젝트 타입 개념

‘object’ 라는 자료형은 어떤 타입의 변수든 할당하여 사용할수 있다.

마치 C/C++ 의 ‘auto’ 나 C#의 ‘var’ 처럼 말이다. 물론 같은것은 아니다. 전혀 다른 개념이다. auto, var 키워드는 타입을 추론하는 자동변수들이다. 런타임이 아닌 컴파일단계에서 타입이 정해지도록 지정해 놓는 녀석들인 것이다. 즉, 타입을 ‘명시적’으로 지정하지 않아도 대입된 값에 따라 컴파일러가 추론을 해준다는 것이다

 object 타입은 어떤 값이든 대입할때는 ‘명시적’ 으로 타입을 지정하지 않아도 되지만, 사용할때는 타입을 ‘명시’ 해주어야 한다.

.

object obj = 30.0f; float temp1 = obj; // error 
float temp2 = (float)obj; // non-error

 

상자에는 어떤 물건이든 담을수 있을것이다. 상자에 어떤걸 담느냐에 따라 상자의 가치는 변한다.

여기서 상자가 object 타입의 변수이고, 담는 물건이 object 타입을 결정할 값이다. 즉, 상자인 object 타입의 변수에 어떤 (가치)물건을 담든 잘 사용할수 있다는 것이다. 상자는 단지 물건을 담고(참조) 있을 뿐이다. 사용할때 어떤 물건인지 알려주면(명시적 타입 지정) 된다.

Boxing(박싱) 이란 단어 그대로 물건(값 형식)을 박스(참조 형식)에 넣어주는것을 말한다. 값 형식 => 참조 형식

Unboxing(언박싱) 이란 단어 그대로 박스(참조 형식)에서 물건(값 형식)을 꺼내는 것을 말한다. “이 상자에는 어떤 가치(타입) 의 물건이 들어있으니 꺼내라” 라는 것이다. 참조 형식 => 값 형식

objcet 형이 이러한 작동이 가능한 이유는, 모든 타입(int, float, string, char, 구조체…) 의 최상위 부모이기 때문이다.(object = System.Object / 상속) c/c++ 에서 최상위 부모로 포인터를 받고, 캐스팅해서 사용했던 포인터의 개념을 생각하면 쉬울것이다.

using System;

class Program
{
    static void Main()
    {
        // 값형
        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
    }
}