본문 바로가기
🌐 유니티 (Unity)

Day 16 - C# (참조형, 박싱, 람다, 델리게이트)

by shin0707 2024. 5. 1.
728x90
반응형

  • 주제

1. 값형, 참조형

2. 박싱, 언박싱(값형과 참조형 사이의 변환)

3. 람다 & 델리게이트


  • 공부내용

1. 값형, 참조형 (변수가 데이터를 저장하는 방식이 서로 다름)

1-1. 값형

변수에 값을 직접 저장 --> (스택 메모리만 사용)

변수가 실제 데이터를 보유, 할당하거나 전달 시 값이 복사됨.

ex) int, float, string, double, bool 등

struct MyStruct
{
    public int Value;
}

MyStruct struct1 = new MyStruct(); // 동적할당
struct1.Value = 10;

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

struct2.Value = 20;               //(struck1 변수에 영향을 주지 않음)

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

 

1-2. 참조형

변수에 데이터에 대한 참조(데이터 값이 저장되어 있는 곳의 주소)를 저장 --> (스택, 힙 둘다 사용)

해당 변수를 할당하거나 전달 시 참조(메모리 위치주소)가 복사됨.

클래스의 변수값을 복사하면, 원래 변수값과 복사된 변수값은 한 배를 탄 것이다.

그래서 원래 변수값이나 복사된 변수값이 바뀌면 같이 바뀌게 된다.

 

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

class Apple
{
    public int Value;
}

//static void Main(string[] args)
Apple apple1 = new Apple();
apple1.Value = 10;

Apple apple2 = apple1; // apple2는 apple1의 메모리주소를 복사

apple2.Value = 20;  // apple1과 같은 메모리주소를 가지고 있는 apple2의 변수값이 변하면 apple1도 변함

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

 

 

***클래스의 원래 변수값과 복사된 변수값이 한 배를 타지 않고, 각각 다른 배를 타려면 어떻게 해야할까?

-->깊은 복사로 다른 주소에 변수값을 저장하면 된다.

 

***깊은 복사란?

2024.05.03 - [유니티] - Day 18 - C# (얇은 복사, 깊은 복사, ICloneable)


2. 박싱, 언박싱(값형과 참조형 사이의 변환)

-박싱: 값형 --> 참조형으로 변환하는 과정 (object를 사용)

-언박싱: 참조형 --> 값형으로 변환하는 과정 (값형의 본래 자료형을 사용)

//값형을 참조형으로 변환하는 리스트 생성
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로 언박싱

 


3. 델리게이트 & 람다

3-1. 델리게이트

델리게이트는 메서드를 참조(메서드가 저장되어 있는 위치를 저장)하여,

델리게이트를 사용하면 해당 메서드를 매개변수로 전달하거나 변수에 할당할 수 있다.

 

3-2. 델리게이트 구현(메서드 등록 -> 사용)

델리게이트가 참조할 메서드의 형식은 델리게이트와 같아야 한다.

public delegate int 델리게이트명(int x, int y)

public int 메서드명(int x, int y)

delegate int Calculate(int x, int y);        

static int Add(int x, int y)
{
    return x + y;
}

class Program
{
    static void Main()
    {
        // 델리게이트 변수(calc)에 메서드 등록
        Calculate calc = Add;

        // 델리게이트 사용
        int result = calc(3, 5);
        Console.WriteLine("결과: " + result);
    }
}

 

3-3. event 와 함께 사용

event는 할당연산자( = )를 사용할 수 없으며, 클래스 외부에서는 호출이 불가능하다.

(텍스트 게임에 활용해볼 수 있을 것 같다)

// 델리게이트 선언
public delegate void EnemyAttackHandler(float damage);

// 적 클래스
public class Enemy
{
    // 공격 이벤트
    public event EnemyAttackHandler OnAttack;

    // 적의 공격 메서드
    public void Attack(float damage)
    {
        // 이벤트 호출
        OnAttack?.Invoke(damage);
				// null 조건부 연산자
				// null 참조가 아닌 경우에만 멤버에 접근하거나 메서드를 호출
    }
}

// 플레이어 클래스
public class Player
{
    // 플레이어가 받은 데미지 처리 메서드
    public void HandleDamage(float damage)
    {
        // 플레이어의 체력 감소 등의 처리 로직
        Console.WriteLine("플레이어가 {0}의 데미지를 입었습니다.", damage);
    }
}

// 게임 실행
static void Main()
{
    // 적 객체 생성
    Enemy enemy = new Enemy();

    // 플레이어 객체 생성
    Player player = new Player();

    // 플레이어의 데미지 처리 메서드를 적의 공격 이벤트에 추가
    enemy.OnAttack += player.HandleDamage;

    // 적의 공격
    enemy.Attack(10.0f);
}

 

 

3-4. 델리게이트를 람다식으로 할당

람다를 사용하면 메서드의 이름 없이 메서드를 만들 수 있다. 

그리고 델리게이트를 홀로 사용했을 때보다 코드도 간결해졌다.

using System;

// 델리게이트 선언
delegate void MyDelegate(string message);

class Program
{
    static void Main()
    {
        // 델리게이트 인스턴스 생성 및 람다식 할당
        MyDelegate myDelegate = (message) =>
        {
            Console.WriteLine("람다식을 통해 전달된 메시지: " + message);
        };

        // 델리게이트 호출
        myDelegate("안녕하세요!");

        Console.ReadKey();
    }
}
728x90
반응형

loading