Deff_Dev
[Unity/C#] 일반화 프로그래밍 (Generic) 본문
일반화란 ?
- 특수한 개념으로부터 공통된 개념을 찾아 묶는 것
이러한 일반화를 이용하는 프로그래밍이 일반화 프로그래밍 !
일반화 프로그래밍의 일반화 대상 ▶ 데이터 형식 (Data Type)
일반화 함수
예를 들어 배열을 복사하는 함수가 있다고 해보자.
int 형의 배열을 복사할 수 도 있지만 float, string 등 다른 형태의 배열도 복사를 해야 될 때, 해당 함수를 오버로딩해 해결할 것이다.
public void CopyArr(int [] arr, int [] targetArr)
{
for(int i = 0; i< arr.Length; i++)
{
targetArr[i] = arr[i];
}
}
public void CopyArr(string[] arr, string[] targetArr)
{
for (int i = 0; i < arr.Length; i++)
{
targetArr[i] = arr[i];
}
}
public void CopyArr(float[] arr, float[] targetArr)
{
for (int i = 0; i < arr.Length; i++)
{
targetArr[i] = arr[i];
}
}
// 모든 데이터 형식을 오버로딩 해야한다.
이렇게 된다면, 복사해야 될 배열의 데이터 형식이 늘어나면 늘어날수록 오버로딩 함수는 엄청나게 많아질 것이다.
100개의 데이터 타입을 복사해야 한다면 100개의 함수를 만들어야 할 수 도 있다.
이때, 일반화 함수를 사용하게 된다면 여러 형식에 맞춰 복사 함수를 오버로딩할 필요가 없어진다.
일반화 함수를 작성하는 방법은 다른 일반 함수 작성법과 크게 다르지 않고, 데이터 형식에 T가 들어간다.
위 함수를 일반화 함수로 바꿔보자.
private void Awake()
{
int [] arr = new int[4];
int [] targetArr = new int[4];
CopyArr<int>(arr, targetArr);
}
public void CopyArr<T>(T[] arr, T[] targetArr)
{
for (int i = 0; i < arr.Length; i++)
{
targetArr[i] = arr[i];
}
}
일반 함수와 일반화 함수의 차이점은 데이터 형식이 T라는 점, 이름 뒤에 형식 매개변수 <T>가 들어간다는 점이다.
함수를 호출할 때, <> 안에 데이터 형식을 지정해준다면 T는 해당 데이터 형식으로 치환되서 함수가 실행된다.
이렇게 일반화 함수를 사용한다면, 데이터 형식의 유연하게 처리할 수 있다,
일반화 클래스
클래스의 데이터 형식을 일반화한 클래스이다.
public class CopyArr_Int
{
private int[] arr;
public void CopyArr(int[] targetArr)
{
for (int i = 0; i < arr.Length; i++)
{
arr[i] = targetArr[i];
}
}
}
public class CopyArr_String
{
private string[] arr;
public void CopyArr(string[] targetArr)
{
for (int i = 0; i < arr.Length; i++)
{
arr[i] = targetArr[i];
}
}
}
위처럼 클래스 안에 작성된 기능은 똑같지만 데이터 형식이 다르다고 할 때, 데이터 형식이 추가되면 추가될 수록 클래스가 늘어날 것 이다.
이때, 일반화 클래스를 사용해보자 !
public class CopyArr <T>
{
private T[] arr;
public void Copy(T[] targetArr)
{
for (int i = 0; i < arr.Length; i++)
{
arr[i] = targetArr[i];
}
}
}
public class Test
{
public void Ts() // 사용
{
CopyArr<int> copy = new CopyArr<int>();
int[] target = new int[4];
copy.Copy(target);
}
}
일반화 클래스를 통해 클래스에서도 데이터 형식을 유연하게 처리할 수 있다.
일반화 클래스를 이용한 싱글톤 글이다.
형식 매개변수(T) 제약시키기
형식 매개변수 T가 특정 조건에만 대응하도록 제약을 줄 수 있다.
where 형식 매개변수 : 제약 조건
일반화 함수나 클래스 이름 뒤에 where 형식 매개변수 : 제약 조건을 작성하면 된다.
제약 | 설명 |
where T : struct | T는 값 형식이어야 한다. |
where T : class | T는 참조 형식이어야 한다. |
where T : new() | T는 반드시 매개변수가 없는 생성자가 있어야 한다. |
where T : 부모 클래스 이름 | T는 명시한 기반 클래스의 파생 클래스여야 한다. |
where T : 인터페이스 이름 | T는 명시한 인터페이스를 반드시 구현해야 한다. (복수 명시 가능) |
where T : U | T는 또 다른 형식 매개변수 U로부터 상속받은 클래스여야 한다. |
where T : 부모 클래스 이름 제약 조건 예제
struct, class, 인터페이스 이름 제약 조건도 위 글의 기능과 비슷하므로 설명을 생략하겠다.
where T : new()
public class Character
{
string name;
public Character()
{
name = "Deff";
}
}
public class Test
{
public void Ts() // 사용
{
Character character = CreateInstance<Character>();
}
public T CreateInstance<T>() where T : new()
{
return new T();
}
}
new()는 매개 변수가 없는 기본 셍성자를 가진 어떤 클래스의 객체라도 생성해준다.
where T : U
using UnityEngine;
using System;
public class Base { }
public class Derived:Base { }
public class Add:Base { }
public class BaseArray<U> where U : Base
{
public U [] Array { get; set; }
public BaseArray(int size)
{
Array = new U[size];
}
public void CopyArray<T>(T[] Source) where T : U
{
Source.CopyTo(Array, 0);
}
}
public class Test : MonoBehaviour
{
private void Start()
{
BaseArray<Derived> derArr = new BaseArray<Derived>(3);
BaseArray<Base> baseArr = new BaseArray<Base>(3);
BaseArray<Derived> derArr2 = new BaseArray<Derived>(3);
derArr2.CopyArray<Derived>(derArr.Array);
}
}
U는 Base를 상속 받아야 하고,(where U : Base) T는 U를 상속받아야 한다. (where T : U)
'Unity(유니티) > 유니티 공부' 카테고리의 다른 글
[Unity/C#] foreach문에서 컬렉션 수정할 때, 생기는 오류 (0) | 2024.07.04 |
---|---|
[Unity/C#] 이벤트 호출 안될 때 (0) | 2024.07.04 |
[Unity/C#] AudioMixer를 이용한 볼륨 조절 (0) | 2024.06.26 |
[Unity/C#] 확률 구하기 (0) | 2024.06.24 |
[Unity/C#] AES 암호화 알고리즘 (0) | 2024.06.23 |