Unity & C#

List<T>를 상속받아 CustomList<T> 만들기

왼손잡이개발자 2021. 9. 16. 20:51

 

List를 사용 할 때 마다 이런 기능이 있었으면 좋겠다고 생각한 적이 있다. 바로 리스트에 아이템이 추가되거나 제거 되었을 때 이벤트를 실행 시킬 수 있으면 여러 용도로 사용할 수 있겠다는 생각을 했다. 그래서 C#의 List<T>를 상속받는 자신만의 CustomList를 만들어 보았다.

 

CustomList.cs

먼저 CustomList.cs 를 생성해서 C#의 List<T>를 상속받는다.

using System.Collections.Generic;

namespace CustomList
{
	public interface ICustomListable
	{
	}


	public class CustomList<T> : List<T> where T : ICustomListable
	{
		public delegate void CustomListEventHandler<T>(T listItem);
		public event CustomListEventHandler<T> onAdded;
		public event CustomListEventHandler<T> onRemoved;

		public new void Add(T newItem)
		{
			base.Add(newItem);
			onAdded?.Invoke(newItem);
		}

		public new void Remove(T tobeRemoved)
		{
			base.Remove(tobeRemoved);
			onRemoved?.Invoke(tobeRemoved);
		}

	}
}

CustomList<T> 클래스는 List<T>를 상속받고 T는 인터페이스 ICustomListable를 구현하고 있어야한다.

그리고 CustomList<T>에 아이템을 추가할 때는 public new void Add(T newItem)을 통해서 추가되는데 여기서 포인트는 "new"를 사용하여 기존 C# List<T>가 아닌 CustomList<T>의 Add 메소드를 재정의 해준다. 추가되었을 땐 onAdded 이벤트가 호출된다. Remove도 같은 원리이다. 

 

CustomListManager.cs

다음은 Monobehavior를 상속받는 CustomListManager를 만들어 component로 쓰이는 방법을 보겠다. 

using UnityEngine;

namespace CustomList
{
	public class Fruit : ICustomListable
	{
		private string _name;
		public string name => _name;

		public Fruit(string fruitName)
		{
			_name = fruitName;
		}
	}

	public class CustomListManager : MonoBehaviour
	{
		private CustomList<Fruit> fruits = new CustomList<Fruit>();

		private void OnEnable()
		{
			fruits.onAdded += OnFruitAdded;
			fruits.onRemoved += OnFruitRemoved;
		}

		private void OnFruitAdded(Fruit fruit)
		{
			print(fruit.name + " added to the list!");
		}

		private void OnFruitRemoved(Fruit fruit)
		{
			print(fruit.name + " removed from the list!");
		}


		private void Start()
		{
			Fruit apple = new Fruit("Apple");
			fruits.Add(apple);

			Fruit pineapple = new Fruit("Pineapple");
			fruits.Add(pineapple);

			Fruit orange = new Fruit("Orange");
			fruits.Add(orange);
		}

		private void Update()
		{
			if (Input.GetMouseButtonDown(0))
			{
				if (fruits.Count == 0)
				{
					print("No Fruit to be removed!");
					return;
				}

				RemoveTheLastFruit();
			}
		}

		private void RemoveTheLastFruit()
		{
			int lastIndex = fruits.Count - 1;
			Fruit lastFruit = fruits[lastIndex];
			fruits.Remove(lastFruit);
		}
	}

}

예시로 Fruit이라는 클래스를 만들어 CustomList<Fruit> fruits 라는 제작리스트에 추가해보았다. fruits의 onAdded 이벤트에 private void OnFruitAdded를 등록했기 때문에 (fruits.onAdded += OnFruitAdded) 추가될때마다 OnFruitAdded 함수에서 리스트에 아이템이 추가되었을 때 다양한 활용을 해볼수있다. 여기 예시에서는 그냥 fruit의 name을 print 되게 해보았다.

Update() 에서는 마우스 클릭을 했을 시 마지막 index의 fruit이 리스트에서 remove 되게 해주었고, onAdded 이벤트와 동일하게 onRemoved 이벤트가 발동되어서 remove 된 fruit의 name이 print 되게 구현하였다.

 

나는 CustomList에서 추가,제거 이벤트만 구현했는데 이것 외에도 더 다양한 방법으로 확장 할 수 있으거라 생각한다.