1. 일반화(Generalization)란?
'일반화'는 간단히 말해 서로 다른 개념에서 공통점을 찾는 것이다.
'A' 와 'B', 'C'는 분명 다른 단어이지만 '영어'라는 공통점을 가지며
"ABC"와 "가나다"는 분명 다른 글자이지만 '문자'라는 공통점을 가진다.
이렇듯 어떤 개념을 포괄하는 공통된 개념을 찾아 서러 다른 개념들을 하나로 묶어 줄 수 있다.
이것을 일반화(Generalization)라고 한다.
2. 일반화 메소드
그럼 프로그래밍에서도 이런 일반화가 가능하지 않을까?
코드의 서로 다른 개념들 사이에서 공통적인 개념을 찾아 하나의 코드로 묶어주는 것 말이다.
예를들어 int, float, string 등은 분명 다른 타입이다.
하지만 이들은 '변수'라는 개념으로 묶어줄 수 있다.
이전에는 int, float, string을 다른 개념으로 보고 다른 코드를 사용하였다면
이제는 이들을 변수라는 하나의 개념으로 보고 하나의 코드로 만들어 줄 수 있겠다.
서로 다른 타입이 여러개 있을 때 이들을 출력하는 메소드를 일일이 만들어 주는 것보단
위와 같이 일반화 과정을 거쳐 하나의 메소드로 만들어주는 것이 훨씬 효율적이다.
이를 일반화 메소드하고 하며 일반화 메소드는 다음과 같이 호출할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
namespace Cs_Lecture
{
class Program
{
static void print<T>(T value)
{
Console.WriteLine(value);
}
static void Main(string[] args)
{
int age = 29;
float height = 178.1f;
string name = "Mr.W";
print<int>(age);
print<float>(height);
print<string>(name);
}
}
}
|
print<T> 에서 T 에 원하는 타입을 지정하면 print 메소드 내부의 T 가 전부 지정한 변수로 치환되며
지정된 변수로 메소드가 실행된다.
즉, 위 예제에서처럼 int형을 지정하면 int형 데이터가 출력되고
float형을 지정하면 float형 데이터가, string형을 지정하면 string형 데이터가 출력되는 것이다.
(여기에서 T 는 형식매개변수하고 하여 형식(타입)을 지정해주는 역학을 한다.
하지만 형식매개변수로 반드시 T 만 사용가능한 것은 아니며
단순히 치환을 해주는 문자이기 때문에 T 외에 어떤 문자도 사용가능하다. 한글도 가능.)
3. 일반화 클래스
클래스도 마찬가지로 일반화된 클래스를 만들 수 있다.
예를 들어 여러 타입의 자료구조 클래스를 만든다고 했을 때
타입마다 서로 다른 클래스를 만드는 것은 상당히 비효율적이다.
이럴 때에 일반화 메소드를 만들었던 거과 마차가지로 모든 타입을 포괄하는
하나의 일반화 클래스를 만들 수 있다.
간단하게 예제를 만들어 보면 다음과 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
namespace Cs_Lecture
{
class List<T>
{
public T[] arr;
public List() { arr = new T[1]; }
}
class Program
{
static void Main(string[] args)
{
List<int> list1 = new List<int>();
list1.arr[0] = 10;
List<float> list2 = new List<float>();
list2.arr[0] = 2.2f;
List<string> list3 = new List<string>();
list3.arr[0] = "일반화 클래스";
Console.WriteLine(list1.arr[0]);
Console.WriteLine(list2.arr[0]);
Console.WriteLine(list3.arr[0]);
}
}
}
|
4. T 변수 제약조건 만들기
지금까지 만든 일반화 메소드와 일반화 클래스는 모든 타입의 변수를 처리할 수 있었다.
다시 말해(타입)을 지정하는 매개변수 T 는 모든 타입으로 치환이 가능했다.
하지만 만약에 이 매개변수 T 를 특정 조건을 갖춘 타입으로만 치환이 가능하도록
제한하고 싶다면 어떻게 해야할까?
이때 사용하는 것이 "Where T : 제약조건" 이다.
'where T' 라는 건 T 가 어디에 있어야 한다(어디에 속해야 한다)라는 의미로 해석될 수 있겠다.
즉 where이라는 키워드로 T 의 타입 범위를 지정해주는 것이다.
where 형식매개변수 : 제약조건
class List<T> where T : class
{
// ...
}
void Print<U> where U : struct
{
// ...
}
예를 들어 'where T : class'라 하면 "형식 매개변수 T 의 타입은 class여야 한다." 라는 것이고
'where T : struct'라 하면 "T 의 타입이 값(int, float 등등...)이어야 한다.' 라는 것이다.
이외에더 형식매개변수의 제약조건은 여러가지가 있다.
where T : new() | T 는 매개변수가 없는 생성자를 가진 타입이어야 한다. |
where T : 클래스 이름 | T 는 지정한 클래스이거나 이를 상속받는 클래스이어야 한다. |
where T : 인터페이스 이름 | T 는 인터페이스를 상속받는 클래스 이어야 한다. |
where T : U | T 는 형식매개변수 U 의 타입이거나, 이를 상속받는 클래스 이어야 한다. |
간단한 예제를 보면 다음과 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
namespace Cs_Lecture
{
class Parent
{
public string name { set; get; }
public Parent() { name = "부모클래스"; }
}
class Children : Parent
{
public Children() { name = "자식클래스"; }
}
class List<T> where T : Parent
{
public T[] array;
public List() { array = new T[2]; }
}
class Program
{
static void Main(string[] args)
{
List<Parent> list = new List<Parent>();
}
}
}
|
'IT 야놀자 > C #' 카테고리의 다른 글
무명 형식, 무명 메소드 (0) | 2019.11.05 |
---|---|
델리게이트 (Delegate) - 콜백, 체인 (0) | 2019.11.04 |
일반화 컬렉션 - List, Queue, Stack, Dictionary (0) | 2019.10.31 |
컬렉션 (Collection) - ArrayList, Queue, Stack, Hashtable (0) | 2019.10.28 |
프로퍼티 (Property) (0) | 2019.10.25 |