Chapter 9-1. 기타문법 : Generic(일반화) + object, 박싱/언박싱, where
카테고리: C Sharp
태그: C Sharp Programming
인프런에 있는 Rookiss님의 강의 Part1: C# 기초 프로그래밍 입문 를 듣고 정리한 필기입니다. 😀
👩🏼 Generic
클래스 정의시 여러가지 자료형에 대해 일반화.
class MyList
{
int [] arr = new int[10];
public int GetItem(int i)
{
return arr[i];
}
}
class MyfloatList
{
float [] arr = new float[10];
public float GetItem(int i)
{
return arr[i];
}
}
class MyMonsterList
{
Monster [] arr = new Monster[10];
public Monster GetItem(int i)
{
return arr[i];
}
}
같은 내용의 클래스라도 여러가지 자료형의 경우로 나누어야 한다면 위와 같이 일일이 나열해야 한다. 일반화시킬 필요가 있다.
object와 박싱/언박싱
Obejct
👉int
,float
같은 모든 자료형 및 모든 클래스의 조상. (사용자 지정 클래스의 조상도Object
이다.)
/* 박싱 */
object obj = 3;
object obj2 = "Hello World";
object
타입은 기본 자료형들을 비롯한 모든 클래스들의 조상이기 때문에 업 캐스팅 개념으로 int
, string
같은 기본 자료형들을 object
하나로 참조할 수 있다. 이 과정을 박싱 이라고 한다.
/* 언박싱 */
int num = (int)obj;
string str = (string)obj2;
다시 원래 자료형으로 되돌릴 땐 다운 캐스팅 개념으로 형변환 해주면 된다. 이 과정을 언박싱 이라고 한다.
class MyList
{
object [] arr = new object[10];
}
그러면 자료형들을 일반화시킬 때 위와 같이 object
를 사용하면 되지 않을까?
그래도 되긴 하지만, 박싱/언박싱 과정은 성능상 느리다. 따라서 비효율적이다. object
는 언제나 데이터를 참조하는 방식으로 저장하기 때문이다. 즉 진짜 데이터는 힙 메모리에 저장되고 변수 obj
엔 그 주소가 저장된다.
int n = 3;
object obj = 3; // 박싱
int num = (int)obj; // 언박싱
int
인n
의 데이터3
은 스택 메모리의n
영역에 직접 저장된다.object
인obj
가 참조하는 데이터인3
은 힙 메모리에 저장되며, 스택 메모리의obj
영역엔 이 힙 메모리의 주소가 저장된다.- 박싱 👉 힙 메모리를 할당받는 과정이 필요하므로 성능면에서 깎임.
- 힙 메모리에 있는
obj
가 참조중인 데이터3
을 복사해 가져와 스택 메모리의num
영역에 직접 저장한ㄷ.- 언박싱 👉 힙 메모리에 있는 데이터를 빼내어 스택 영역으로 옮기는 과정이 필요하므로 이 역시 성능면에서 깎임.
결론 : object
는 박싱 언박싱 과정 때문에 성능이 좋지 않으므로 Generic
을 통해 일반화를 한다. Generic
은 컴파일 타임에 결정되기 때문에 더 빠르다.
Generic 일반화
Generic 클래스
class MyList <T>
{
T[] arr = new T[10];
public T GetItem(int i)
{
return arr[i];
}
}
class Program
{
static void Main(string[] args)
{
MyList<int> myIntList = new MyList<int>();
MyList<Monster> myMonsterList = new MyList<Monster>();
}
}
자료형들을 일반화하여 T
자리에 여러 자료형 타입이 올 수 있게 된다!
인자 추가
class MyList <T, M>
{
public T GetItem(M m)
{
return T[m];
}
}
Dictionary<int, Monster> dic = new Dictionary<int, Monster>();
일반화 할 특정 인자가 더 필요하다면 <class MyList <T, M>
이런식으로 T
말고 추가 문자를 더 써주면 된다. Dictionary 자료구조도 이렇게 Generic 인자를 2 개 사용하는 경우다.
where
C#에만 있는 문법으로 특수화를 할 때 사용한다. 구체화할 때
where T : type
👉T
를type
타입으로만 구체화하도록 제약을 둔다.
class MyList <T> where T : Monster
{
}
종류 | 설명 |
---|---|
where T : struct | T 는 Call by Value 형식어야 한다. int , float , struct 등등.. |
where T : class | T 는 Call by Reference 형식어야 한다. 모든 클래스, 인터페이스, 대리자 또는 배열 형식에도 적용된다. 따라서 기본 자료형은 들어올 수 없다. |
where T : new() | T 는 매개 변수 없는 디폴트 생성자를 반드시 가지고 있어야 한다. where T : Monster, new() 는 Monster 타입의 클래스로만 구체화될 수 있으며 구체화될 땐 디폴트 생성자를 호출해야 한다. |
where T : 특정 클래스 이름 | T 는 해당 클래스와 해당 클래스의 자식 클래스 타입의 객체여야만 한다. where T : Monster 는 Monster와 Monster를 상속받는 Orc, Slime 등등의 클래스 타입의 객체로만 구체화될 수 있다. |
where T : 인터페이스 이름 | T 는 명시한 인터페이스를 반드시 구현해야 한다. 인터페이스를 여러개 명시해줄 수도 있다. |
where T : U | T 는 또 다른 형식 매개 변수 U 와 일치하거나 U 로부터 상속 받은 클래스여야 한다. |
Generic 일반 함수
class Program
{
static void Test<T>(T input)
{
Console.WriteLine(input);
}
static void Main(string[] args)
{
Test<int>(3);
Test<float>(3);
}
}
이렇게 함수도 일반화할 수 있다. 함수 이름 오른쪽에 <T>
만 붙여주고 일반화 할 자료형 자리를 T
로 대체해주면 된다. 함수를 호출할 때도 함수 이름 오른쪽에 <T>
만 붙여주면 된다. where
로 제한도 할 수 있다.
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기