삽질의 현장/- .NET

#050_닷넷(.NET)_.Net Framework 기본 - 제네릭(Generic) 소개

shovelman 2015. 10. 30. 20:58


안녕하세요 삽잡이입니다.


이번 시간에는 제네릭에 대해서 알아보려고 합니다.


Collection은 일반적으로 자료구조라고 부릅니다.

개념적으로 클래스나 실질적으로 객체를 일컷는 용어이지요.

Generic은 일반적으로 위의 뜻에서 '일반화'가 붙은 것입니다.


왜 일반화가 들어갈까요?



일반적으로 좌측은 collection, 우측은 제네릭이라고 합니다.


둘 다 자료구조 클래스이니 collection입니다.

제네릭도 collection입니다.

하지만, <T>가 붙어있죠...

즉, 일반화 기능이 추가되어있는 것입니다.



Array가 만약, int[] 형식을 담고있다면 이는 int형 Array입니다.

하지만, 제네릭을 사용하게 되면 T형 Array로써 사용자가 타입을 결정할 수 있게 됩니다.

T를 결정할 수 있다 이겁니다.


뭐.. 별거 없습니다.

단지, ~<T> 까지가 이름이 되는 것입니다.


메서드를 만들 때에도 똑같습니다.

C#의 경우 함수이 이름 뒤에도 제네릭 함수임을 명시해줘야합니다.


 



Collection을 

Collection Class들이라고 만들어져 있는 클래스들이 있습니다.

뭐.. ArrayList라던지, Queue와 같은 클래스들 말입니다.


자료구조는 어떤 특정 타입만을 저장하는 것이 아닙니다.

즉, 어떤 타입이던 자장할 수 있는 모든 타입이 보관 가능하도록 object로 만들어져있습니다.

그런데 보통 데이터를 많이 보관하겠지요.


데이터의 추상화는 보통 struct입니다. 즉, 값 형식이라는 것입니다.

그러면 다 object로 보관할 때, 꺼내올 때 boxing, unboxing 작업이 일어나게됩니다.



어떤 객체든지 담을 수 있습니다.

하지만, 너무 비효율적이고 느립니다.


계속해서 boxing, unboxing 작업을 합니다...

이는 제네릭이 나오기 전에 사용했던 클래스들입니다.

아무튼... 이런 비효율적이고 느린 단점에 의해서 제네릭이 만들어진 것입니다.


Collection 클래스들은 이제 잘 사용하지 않습니다.

제네릭을 통해 만들게 되면 그 형식에 맞도록 정확하게 보관할 수 있기 때문입니다.


C++의 Template이 두 가지의 종류가 있듯이 

C#의 제네릭 또한 두 가지로 나뉠 수 있습니다.

바로, 이 제네릭은 클래스 형식의 제네릭과 함수 형식의 제네릭이 있습니다.

닷넷은 사실 잘 안나눕니다... 다 제네릭인데... 아무튼...



클래스는 자료구조를 표현하기 위한 컬렉션을 제네릭으로 만든 것입니다.

함수는 문제 해결, 명령어의 나열, 어떤 문제를 해결하기 위한 명령어의 순서등

즉, 알고리즘을 나타냅니다.

알고리즘은 '어떤 문제를 해결하는 절차'라고 말하지요.

코드로 함수를 표현하지 않습니까?

어떤 기능에 대한 명령어의 나열이 바로 함수입니다.


예를 들어 정렬 하고싶다는 필요성이 느낀다면,

알고리즘을 만들지 않겠습니까?

즉, 어떤 식으로 정렬할지에 대해서 절차가 있을 터인데 이를 함수로 만든다 이겁니다.


그런데 정수를 정렬하거나, Rect, Point 등.. 다 절차가 달라질까요?

아닙니다. 그저 타입만 달라질 뿐이지요.

즉, 정렬에 대한 알고리즘이 있다면 절차는 그대로이지만,

데이터의 형식, 데이터의 성질만이 달라진다 이겁니다.


아무튼...

자료를 저장, 보관하기 위해서는 자료구조가 필요한데,

이 자료구조의 형식은 클라이언트가 알고 있으니 

클라이언트가 정할수 있도록 범용적으로 만들면 제네릭 클래스가 되는 것입니다.


그리고 어떤 문제를 해결하기 위한 알고리즘을 함수로 만들었는데,

그 알고리즘이 특정 데이터에서만 동작해서는 안되기 때문에,

범용적인 데이터에서 동작할 수 있도록 

일반화 시켜 만들면 제네릭 함수가 되는 것입니다.


거의 대부분 제네릭 클래스는 자료구조입니다.

자료구조를 표현했지요...

그리고 제네릭 함수의 거의 대부분은 알고리즘을 표현했습니다.


아무튼...

목적은 명확하지만, 어떤 타입인지 언급이 없게 만들면,

즉, 타입에 대해서 언급은 없지만, 알고리즘에 대해서만 구현이 되어있다면

제네릭 함수로 만들어졌다고 말할 수 있습니다.

따라서 제네릭 함수를 만들기 위해서는 범용적인 타입을 받을 수 있으며,

어떤 타입이 들어와도 절차가 변하지 않아야되는 것을 보장해줘야겠지요.


만약, 특수한 경우 꼭 int형만, 꼭 double 형만 사용해야하는 

즉, 특수한 목적의 그 일만하는 클래스라면 해당 이름에 어울리는 클래스를 정의하면 됩니다.


하지만, 어떤 데이터들던지 상관없이 무엇인가 하는 형태로 표현을 하고 싶다면

즉, 추상화 하여 클래스로 만들고 싶다면 

클라이언트가 데이터의 타입을 정하도록 제네릭 클래스를 만들면 됩니다.

자료구조는 변하지 않습니다.

단지, 사용할 클라이언트에게 정하라고 물어볼 뿐이지요...


Mediator라고 중재자 역할을 하는 클래스가 있는데,

즉, 중간 적인 역할을 하는 이 클래스는

이놈 저놈의 기능을 연결해주는 역할을 합니다.

이 Mediator는 제네릭으로 만들지 않습니다.


제네릭으로 만들어지는 것들은 

모두 데이터의 타입이 다양하고, 복합적으로 들어오는 것들입니다.

클래스로 들어온다면 제네릭 클래스,

메서드로 들어온다면 제네릭 메서드로 만들어진다는 것입니다.



타입 안정성이란 무엇일까요?



이처럼 정수만 넣으려 했지만 실수가 들어간 경우를 봅시다.


정수만 넣으려고 했지만, 타입이 불안하지요.

넣을 때에는 모두 object형이기 때문에 상관이 없습니다.

하지만, unboxing 할 때 문제가 생깁니다.

double형의 데이터가 int형으로 형식 변환 될 것 아니겠습니까?


그런데,

제네릭에서는 어떤 문제가 발생하지 않습니다.



제네릭은 바로 에러를 때립니다.

즉, 타입 안전성이 더 견고하다는 뜻입니다.



마지막으로...

제네릭은 열거형이 낄 수 없습니다.(?)

왜냐하면, 열거형은 값입니다.

상수를 표현하고자 만든 것이 열거형이지요.

열거형 타입은 제네릭의 T로 설정한다는 자체가 말이 되지 않습니다.

상수 형식을 넣게 되는것이니깐 말입니다..


아무튼...

열거형 빼고 모든 타입이 가능합니다.

즉, 제네릭의 T에 올 수 있다 이겁니다.


그리고 제네릭의 사용되는 T를 Token이라고 해서

'형식 매개변수', '자리 표시자'라고 부르는데 뭐... 자리 표시자가 더 많이 쓰입니다.

아무튼.. 이렇게 공식용어로 부릅니다.


이번 시간은 여기까지 하도록 하겠습니다.


이상 삽잡이였습니다!