확인 문제
using System;
class Program
{
// 델리게이트 정의
public delegate int MyCallback(int a, int b);
// 덧셈 메서드
static int Add(int a, int b)
{
return a + b;
}
// 곱셈 메서드
static int Multiply(int a, int b)
{
return a * b;
}
static void Main(string[] args)
{
MyCallback MathOperation;
MathOperation = Add;
Console.WriteLine(MathOperation(3, 4));
MathOperation = Multiply;
Console.WriteLine(MathOperation(7, 5));
}
}
1. 위 코드의 출력 결과는 무엇인가요? 그 이유는 무엇인가요?
출력 결과▼
7
35
이유 : `MyCallback`이라는 델리게이트는 `int`형 반환값과 `int`형 두 개의 매개변수를 가지는 메서드를 대신 호출할 수 있습니다. 델리게이트는 메서드를 매개변수로 전달할 수 있게 해줍니다. `MathOperation`을 `Add` 메서드로 지정했으므로 `Add` 메서드를 호출하여 `3`과 `4`를 더해 결과가 `7`로 나왔고, 이후 `MathOperation`을 `Multiply` 메서드로 지정했으므로 `Multiply` 메서드를 호출하여 `7`과 `5`를 곱해 결과가 `35`가 나온 것입니다.
2. 위 코드의 Main 함수를 아래처럼 바꿔도 같은 방식으로 동작할까요? 그 이유는 무엇인가요?
static void Main(string[] args)
{
Func<int, int, int> MathOperation;
MathOperation = Add;
Console.WriteLine(MathOperation(3, 4));
MathOperation = Multiply;
Console.WriteLine(MathOperation(7, 5));
}
네 같은 방식으로 동작합니다. `Func`는 반환형과 매개변수 타입을 정의하는 델리게이트로, 위에서 사용한 `MyCallback` 델리게이트와 동일한 역할을 수행합니다. 마지막 매개변수는 반환 형식을 정의합니다.
3. 델리게이트를 사용하여 메서드를 매개변수로 전달하는 장점은 무엇인가요?
- 동일한 코드 블록이 다양한 메서드를 호출할 수 있으므로 유연성이 향상됩니다.
- 코드의 중복을 줄이고 유지보수를 쉽게할 수 있습니다.
- 비동기 작업이나 이벤트 처리 시 콜백 메서드를 쉽게 구현할 수 있습니다.
- 호출자가 메서드의 구현 세부 사항을 몰라도 되므로, 코드의 캡슐화와 추상화가 향상됩니다.
- 전략 패턴을 쉽게 구현할 수 있습니다.
개인적으로 확장해본 코드▼
using System;
class Program
{
// 델리게이트 정의
public delegate int MyCallback(int a, int b);
// 덧셈 메서드
static int Add(int a, int b)
{
return a + b;
}
// 곱셈 메서드
static int Multiply(int a, int b)
{
return a * b;
}
// 델리게이트를 매개변수로 받는 메서드
static void PerformOperation(MyCallback operation, int x, int y)
{
Console.WriteLine(operation(x, y));
}
static void Main(string[] args)
{
// 델리게이트를 사용하여 메서드를 매개변수로 전달
PerformOperation(Add, 3, 4); // 출력: 7
PerformOperation(Multiply, 7, 5); // 출력: 35
}
}
설명 문제
1. 콜백이란 무엇인가요? 콜백을 사용해본 경험이 있을까요?
콜백이란 특정 작업이 완료된 후 호출되는 함수나 메서드를 말합니다. 주로 비동기 작업이나 이벤트 처리에서 사용됩니다. 콜백 함수는 다른 함수에 매개변수로 전달되어 작업이 완료된 후 실행됩니다.
저는 주로 이벤트에 대한 콜백 메서드 등록으로 사용해봤습니다.
2. 델리게이트(delegate; 대리자)란 무엇인가요?
함수 포인터라고 할 수 있습니다. 델리게이트는 메서드의 참조를 담을 수 있는 형식으로, 특정 메서드를 대신 호출할 수 있습니다. 델리게이트를 사용하면 메서드를 매개변수로 전달하고, 런타임에 메서드를 동적으로 변경할 수 있습니다.
델리게이트는 특히 이벤트 처리, 콜백 메서드, 동적 메서드 호출에 유용합니다.
3. C#의 event란 무엇인가요?
`event`는 특정 작업이나 상태 변화가 발생했을 때 이를 알리기 위해 사용하는 특별한 델리게이트입니다.
이벤트는 델리게이트를 기반으로 하며, `+=` 연산자를 사용하여 이벤트 핸들러를 추가하고(이벤트 구독) `-=` 연산자를 사용하여 제거합니다. 이벤트는 외부에서 직접 호출할 수 없으며, 이벤트를 소유한 클래스 내부에서만 호출할 수 있습니다.
4. Unity에서 사용하는 델리게이트 혹은 이벤트에는 어떤 것이 있나요?
- `Action` 델리게이트 : 반환 값이 없는 메서드를 참조할 수 있습니다. 매개변수를 받을 수 있는 인자의 수는 0에서 16개까지 가능합니다.
- `Func` 델리게이트 : 반환 값이 있는 메서드를 참조할 수 있습니다. 마지막 매개변수는 반환 형식을 정의합니다. 매개변수를 받을 수 있는 인자의 수는 0에서 16개까지 가능합니다.
- `UnityEvent` : 유니티의 이벤트 시스템으로, 인스펙터에서 쉽게 설정할 수 있습니다. `UnityEngine.Events` 네임스페이스에서 제공됩니다.
- `event`(이벤트 핸들러) : 특정 이벤트가 발생할 때 호출될 메서드를 등록하는 데 사용됩니다.
실습 문제
💡 [캐릭터 피격 기능 연결]
레이어가 데미지를 받을 때 여러 기능이 한번에 작동하도록 시스템을 만드려고 합니다.
상태 메시지가 출력되고, 피격 이펙트가 나오며, 피격 사운드가 재생되는 메서드가 구현되어 있는 상황입니다.
- `DisplayStatus` : 데미지 상태를 출력하는 메서드입니다.
- `DisplayHitEffect` : 피격 이펙트를 표시하는 메서드
- `PlayHitSound` : 피격 사운드를 재생하는 메서드
1) TakeDamage 함수 내에서 플레이어가 데미지를 받을 때 이벤트를 발생(Publish)시키는 코드를 작성합니다.
2) DisplayAndSound 클래스의 생성자에서 이벤트 발생 시 호출될 메서드(`DisplayStatus`, `DisplayHitEffect`, `PlayHitSound`)를 연결합니다.
⚠️주의!!!)
조건 : 데미지를 받는 로직을 처리하는 TakeDamage 메서드 안에서 `DisplayStatus`, `DisplayHitEffect`, `PlayHitSound`를 직접 호출하지 않고 코드를 완성해봅시다.
using System;
namespace GameEventExample
{
// 이벤트 데이터를 담는 EventArgs 파생 클래스
public class PlayerDamagedEventArgs : EventArgs
{
public int Damage { get; set; }
}
// 플레이어 클래스
public class Player
{
public int HP { get; private set; } = 100;
// 플레이어가 데미지를 받을 때 발생하는 이벤트를 정의하세요.
public event EventHandler<PlayerDamagedEventArgs> PlayerDamaged;
// 플레이어가 데미지를 받는 메서드
public void TakeDamage(int damage)
{
HP -= damage;
PlayerDamagedEventArgs e = new PlayerDamagedEventArgs { Damage = damage };
// TODO: 이벤트가 등록되어 있는지 확인하고 이벤트를 발생
//
}
}
public class DisplayAndSound
{
public DisplayAndSound(Player player)
{
// TODO : 각각의 이벤트 핸들러를 등록하세요.
//
}
// 데미지 상태를 출력하는 메서드
void DisplayStatus(object sender, PlayerDamagedEventArgs e)
{
Player player = sender as Player;
Console.WriteLine($"Player took {e.Damage} damage!");
Console.WriteLine($"Remaining HP: {player.HP}");
}
// 피격 이펙트를 표시하는 메서드
void DisplayHitEffect(object sender, PlayerDamagedEventArgs e)
{
Console.WriteLine("Displaying hit effect...");
}
// 피격 사운드를 재생하는 메서드
void PlayHitSound(object sender, PlayerDamagedEventArgs e)
{
Console.WriteLine("Playing hit sound...");
}
}
class Program
{
static void Main(string[] args)
{
Player player = new Player();
DisplayAndSound displayAndSound = new DisplayAndSound(player);
// 플레이어가 데미지를 받아 이벤트를 발생
player.TakeDamage(20);
Console.WriteLine($"Player HP: {player.HP}");
}
}
}
구현한 코드▼
namespace GameEventExample
{
// 이벤트 데이터를 담는 EventArgs 파생 클래스
public class PlayerDamagedEventArgs : EventArgs
{
public int Damage { get; set; }
}
// 플레이어 클래스
public class Player
{
public int HP { get; private set; } = 100;
// 플레이어가 데미지를 받을 때 발생하는 이벤트를 정의하세요.
public event EventHandler<PlayerDamagedEventArgs> PlayerDamaged;
// 플레이어가 데미지를 받는 메서드
public void TakeDamage(int damage)
{
HP -= damage;
PlayerDamagedEventArgs e = new PlayerDamagedEventArgs { Damage = damage };
// TODO: 이벤트가 등록되어 있는지 확인하고 이벤트를 발생
PlayerDamaged?.Invoke(this, e);
}
}
public class DisplayAndSound
{
public DisplayAndSound(Player player)
{
// TODO : 각각의 이벤트 핸들러를 등록하세요.
player.PlayerDamaged += DisplayStatus;
player.PlayerDamaged += DisplayHitEffect;
player.PlayerDamaged += PlayHitSound;
}
// 데미지 상태를 출력하는 메서드
void DisplayStatus(object sender, PlayerDamagedEventArgs e)
{
Player player = sender as Player;
Console.WriteLine($"Player took {e.Damage} damage!");
Console.WriteLine($"Remaining HP: {player.HP}");
}
// 피격 이펙트를 표시하는 메서드
void DisplayHitEffect(object sender, PlayerDamagedEventArgs e)
{
Console.WriteLine("Displaying hit effect...");
}
// 피격 사운드를 재생하는 메서드
void PlayHitSound(object sender, PlayerDamagedEventArgs e)
{
Console.WriteLine("Playing hit sound...");
}
}
class Program
{
static void Main(string[] args)
{
Player player = new Player();
DisplayAndSound displayAndSound = new DisplayAndSound(player);
// 플레이어가 데미지를 받아 이벤트를 발생
player.TakeDamage(20);
Console.WriteLine($"Player HP: {player.HP}");
}
}
}
'스파르타 게임개발종합반(Unity) > 기술 면접 대비 꾸준 실습' 카테고리의 다른 글
06. 가비지 컬렉터 - GC(Garbage Collectior) (0) | 2024.07.09 |
---|---|
05. 상속과 인터페이스 (0) | 2024.07.08 |
04. 스택 메모리 vs 힙 메모리 (0) | 2024.07.05 |
02. 객체지향 프로그래밍 (0) | 2024.07.03 |
01. 객체와 한정자 (0) | 2024.07.01 |
댓글