나만의 특별한 리스트를 만들고 싶다고 가정할 때 데이터 형식을 여러가지 지원을 해줘야하는데
무식한 방법으로는 버전마다 하나씩 만들어주는 것
class Program
{
class MyIntList
{
int[] arr = new int[10];
}
class MyFloatList
{
float[] arr = new float[10];
}
//......
}
이런식으로 하나씩 다 만드는 것은 너무 비효율적이다.
static void Main(string[] args)
{
object obj = 3;
object obj2 = "hello world";
int num = (int)obj;
string str = (string)obj2;
}
object의 장점은 모든 타입을 소화 가능 하다는 것인데
그렇다면 var 이라는 타입도 비슷한 동작을 했는데 var과 object는 개념이 다르다.
예를 들어,
var obj4 = "hello world";
var은 그냥 뒤에 string이 온것을 보고 string 타입으로 지정을 해주는 것이다.
뒤에 뭐가 오냐에 따라 알아서 변환을 해준다고 생각하면 된다.
그래서 위에 코드는 그냥 string obj4 = "hello world"; 랑 같은 코드인 것이다.
반면에, object는 그냥 object라는 타입이다.
결국에는 상속을 배울 때 클래스를 최상위 부모클래스로 변환이 가능하다는 것을 알았는데
C#에서는 우리가 사용하는 int,string과 같은 타입들이 결국 object를 상속 받아서 구현이 되어있고 그래서 위와 같이 obj , obj2가 가능한것이다.
그러면 모든 타입을 object를 사용하면 되지않을까? 라는 의문이 생긴다.
결론적으로는 속도가 느려진다는 단점이 있다.
int number = 3;
이런식으로 int로 선언한 변수는 stack에서 복사타입으로 3을 저장하며 간단히 사용 할 수있지만
object obj = 3;
이라고 선언할 경우 heap 영역에 메모리를 할당하여 3을 저장하고
int num = (int)obj;
변수 사용하려고 가져오려하면 heap에 저장된걸 stack에 다시 저장하기 때문에 연산 과정이 생기기에 느려진다.
그래서 모든것을 object를 사용하는 것은 무리가 있다.
class MyList<T> //템플릿 클래스
{
T[] arr = new T[10];
public T GetItem(int i)
{
return arr[i];
}
}
static void Test<T>(T input)
{
//템플릿 함수
}
static void Main(string[] args)
{
MyList<int> myIntList = new MyList<int>();
MyList<float> myIntList = new MyList<float>();
MyList<Monster> myIntList = new MyList<Monster>();
Test<int>(3);
}
템플릿은 함수나 클래스를 개별적으로 다시 만들지 않고도 각기 다른 수많은 자료형을 동작 할 수있게 해준다.
C++에서는 안되고 C#에만 되는 기능이 하나 더 있는데 템플릿에 조건을 걸어 줄 수 있다.
class MyList<T> where T : Monster
{
T[] arr = new T[10];
}
예를 들어,
where T : struct -> T는 반드시 값형식
where T : class -> T는 반드시 참조
where T : Monster -> T는 Monster거나 상속받아야한다.
where T : new() -> T는 반드시 기본 생성자를 가지고 있어야한다.