반응형
제네릭(Generic)은 클래스, 인터페이스, 메서드를 작성할 때 사용될 데이터 타입을 미리 지정하지 않고, 사용 시점에 원하는 타입을 지정할 수 있게 해주는 기능이다. 한 마디로, 여러가지 타입을 한방에 대응 가능!
1. 제네릭의 장점
- 타입의 안정성: 컴파일 시점에 타입 체크를 수행하여 런타임 오류를 줄입니다.
- 코드의 재사용: 다양한 데이터 타입에 대해 동일한 로직을 적용할 수 있습니다.
- 성능 향상: 박싱/언박싱 연산을 줄여 성능을 개선합니다.
- 명확성: 코드의 의도를 더 명확하게 표현할 수 있습니다.
2. 제네릭 클래스
제네릭 클래스는 하나 이상의 타입 매개변수를 가진 클래스입니다.
public class GenericList<T> { private List<T> items = new List<T>(); public void Add(T item) { items.Add(item); } public T GetItem(int index) { return items[index]; } } // 사용 예 var intList = new GenericList<int>(); intList.Add(10); var stringList = new GenericList<string>(); stringList.Add("Hello");
2. 제네릭 메서드
제네릭 메서드는 타입 매개변수를 가진 메서드입니다.
public void Print<T>(T inputMessage) { Debug.Log(inputMessage); } void Start() { Print<int>(30); Print<string>("Hello"); }
public static void Swap<T>(ref T a, ref T b) { T temp = a; a = b; b = temp; } // 사용 예 int x = 5, y = 10; Swap(ref x, ref y);
3. 제네릭 제약조건
제네릭 타입에 특정 조건을 부여할 수 있습니다.
public class Calculator<T> where T : struct, IComparable<T> { public T Max(T a, T b) { return a.CompareTo(b) > 0 ? a : b; } } // 사용 예 var calc = new Calculator<int>(); int max = calc.Max(5, 10);
[주요 제약조건]
• where T : struct - 값 타입만 허용
• where T : class - 참조 타입만 허용
• where T : new() - 매개변수 없는 생성자가 있어야 함
• where T : BaseClass - 특정 기본 클래스의 파생 클래스만 허용
• where T : IInterface - 특정 인터페이스를 구현한 타입만 허용
4. 게임 개발에서의 제네릭 활용 예시
[오브젝트 풀링]
public class ObjectPool<T> where T : MonoBehaviour { private Queue<T> pool = new Queue<T>(); private T prefab; public ObjectPool(T prefab, int initialSize) { this.prefab = prefab; for (int i = 0; i < initialSize; i++) { CreateNewObject(); } } public T Get() { if (pool.Count == 0) CreateNewObject(); return pool.Dequeue(); } public void Return(T obj) { obj.gameObject.SetActive(false); pool.Enqueue(obj); } private void CreateNewObject() { T newObj = UnityEngine.Object.Instantiate(prefab); newObj.gameObject.SetActive(false); pool.Enqueue(newObj); } } // 사용 예 ObjectPool<Bullet> bulletPool; bulletPool = new ObjectPool<Bullet>(bulletPrefab, 30); Bullet bullet = bulletPool.Get(); // 총알 사용 로직 bulletPool.Return(bullet);
[데이터 관리 시스템]public interface IGameData { string Id { get; } } public class DataManager<T> where T : IGameData { private Dictionary<string, T> dataMap = new Dictionary<string, T>(); public void AddData(T data) { dataMap[data.Id] = data; } public T GetData(string id) { return dataMap.TryGetValue(id, out T data) ? data : default; } } // 사용 예 public class ItemData : IGameData { public string Id { get; set; } public string Name { get; set; } public int Power { get; set; } } DataManager<ItemData> itemManager = new DataManager<ItemData>(); itemManager.AddData(new ItemData { Id = "sword1", Name = "Steel Sword", Power = 10 }); ItemData sword = itemManager.GetData("sword1");
5. 주의사항
- 과도한 사용 주의: 모든 것을 제네릭으로 만들면 코드가 복잡해질 수 있다.
- 성능 고려: 매우 작은 규모의 작업에 제네릭을 사용하면 오히려 성능 저하가 있을 수 있다.
- 제약조건 활용: 적절한 제약조건을 사용하여 타입의 특성을 최대한 활용할 수 있다.
[정리하며]
제네릭은 C#에서 타입 안전성과 코드 재사용성을 높이는 강력한 도구입니다. 특히 게임 개발에서 다양한 타입의 데이터와 객체를 다룰 때 매우 유용합니다. 오브젝트 풀링, 데이터 관리, 알고리즘 구현 등 다양한 영역에서 제네릭을 활용하면 더 견고하고 유연한 코드를 작성할 수 있습니다.
반응형
'Programming Languages > C# 고급문법' 카테고리의 다른 글
[C# 고급문법] 비동기 프로그래밍 (async, await, Task 클래스) (0) | 2024.09.13 |
---|---|
[C# 고급문법] LINQ (데이터 쿼리) (0) | 2024.09.12 |
[C# 고급문법] 이벤트와 델리게이트: delegate편 (0) | 2024.09.10 |