일반화 프로그래밍
- 특수한 개념으로부터 공통된 개념을 찾아 묶는 것을 "일반화"라고 한다
- 그 일반화하는 대상이 특이하게 데이터 형식이다
void CopyArray( int[] source, int[] target)
{
for(int i = 0; i< source.Length; i++)
target[i] = source[i];
}
CopyArray()메소드를 다음과 같이 오버로딩
void CopyArray( string[] source, string[] target)
{
for(int i = 0; i< source.Length; i++)
target[i] = source[i];
}
만약 이러한 매개변수에 입력되는 배열의 형식만 다르고 내부논리는 똑같은 31가지 버전이 필요하다면?
31가지를 모두 오버로딩하지 않고도 모든 형식을 지원하게 해주자는 아이디어를 바탕으로 만들어진 프로그래밍
패러다임이 바로 일반화 프로그래밍이다
일반화 메소드
- 일반 메소드의 선언 문법과 대부분 비슷
- 대신 일반화할 형식이 들어갈 자리에 구체적인 형식의 이름 대신 "형식 매개변수(Type Parameter)" = T 가 들어간다
한정자 반환형식 메소드이름 <형식매개변수> (매개변수_목록)
{
//
}
위에서 봤던 CopyArray()코드를 일반화 하는 예제 : 데이터형식이 사용된 부분을 T기호로 치환. T는 형식(Type)을 뜻한다
void CopyArray( T[] source, T[] target)
{
for(int i = 0; i< source.Length; i++)
target[i] = source[i];
}
하지만 T는 C#이 지원하는 데이터형식이 아니다 따라서 이 코드를 컴파일하면 에러가 나는 것도 당연하다
이 코드를 컴파일하려면 T가 구체적으로 어떤 형식인지 알려줘야 함. 형식 매개변수를 입력하는 방법은 다음과 같다
메소드 이름 뒤에 홑화살괄호 <와 >를 넣어주고 그 사이에 T를 넣으면 T는 "형식 매개변수"가 된다
그리고 CopyArray()를 호출할 때 <> 사이의 T대신 형식의 이름을 입력하면 컴파일러는 메소드의 나머지 부분에
대해서도 T를 형식 매개변수 값으로 치환한다
void CopyArray<T>( string[] source, string[] target) //메소드 이름뒤에 <T>입력
{
for(int i = 0; i< source.Length; i++)
target[i] = source[i];
}
이제 CopyArray()를 호출
int[] source = { 1, 2, 3, 4, 5 );
int[] target = new int[source.Length];
CopyArray<int>(source, target); //형식매개변수 T에 int를 대입
foreach (int element in target)
Console.WriteLine(element);
일반화 클래스
- 일반화 클래스는 (데이터 형식을) 일반화한 클래스
- 다음과 같이 선언
class 클래스이름 <형식_매개변수>
{
//
}
다음 자료구조 클래스를 보자
Array_int 와 Array_Double은 기능이 같은 클래스지만 내부적으로 사용하는 데이터 형식이 다르다
clas Array_Int
{
private int[] array;
// ...
public int GetElement(int index) {return array[index]; }
}
clas Array_Double
{
private double[] array;
// ...
public double GetElement(int index) {return array[index]; }
}
이 두 클래스는 데이터 형식만 빼고 다른 부분이 모두 같으니 일반화 가능
clas Array_Generic < T >
{
private T[] array;
// ...
public T GetElement(int index) {return array[index]; }
}
다음과 같이 사용
Array_Generic<int> intArr = new Array_Generice<int>();
Array_Generice<double> dblArr = new Array_Generice<double>();
형식 매개변수 제약시키기
일반화 메소드나 일반화 클래스가 입력받는 형식 매개변수 T는 "모든"데이터 형식을 대신할 수 있었다
이렇게 "모든" 형식에 대응할 수 있는 형식 매개변수가 필요할 때도 있지만, 종종 특정 조건을 갖춘 형식에만 대응하는
형식 매개변수가 필요할 때도 있다
where T : 기반_클래스_이름
= MyList<T> 클래스의 형식 매개변수 T에 MyClass(기반클래스)로부터 상속받는 형식이어야 할 것 이라는 제약
class MyList<T> where T: MyClass
{
//...
}
where T : struct =T는 값 형식이어야 할 것
where T : class = T는 참조 형식이어야 함
where T : new() = T는 반드시 매개변수가 없는 생성자가 있어야 한다 (기본 생성자를 가진 어떤 클래스의 객체라도
생성해줌)
되짚어보자면 기본 생성자는 명시적으로 생성자를 따로 구현하지 않는 모든 클래스가 기본생성자를 가진 클래스이다
where T : 인터페이스_이름: T는 명시한 인터페이스를 반드시 구현해야 한다. 인터페이스_이름에는 여러 개의
인터페이스를 명시할 수 도 있다
where T : U = T는 또 다른 형식 매개변수 U로부터 상속받은 클래스여야 한다
예시)
CopyArray<T>() 는 소속 클래스인 BaseArray<U>의 형식 매개변수 U로부터 T가 상속받아야 할 것을 강제하고 있다
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);
}
}
where T : U 이해안감 자세한 예제 책 참고 pg416
일반화 컬렉션
List<T>
Que<T>
Stack<T>
Dictionary<TKey, TValue>
설명할건 딱히 없고 List와 List<T>의 차이점은
List<T> 클래스는 인스턴스를 만들 때 형식 매개변수를 필요로 한다는 것과 컬렉션에 "아무" 형식의 객체나 마구
집어넣을 수 있던 ArrayList와 달리 List<T>는 형식 매개변수에 입력한 형식 외에는 입력을 허용하지 않는다
그리고 Dictionary<TKey, TValue>는 10장에서 다뤘던 HastTable의 일반화 버전
형식 매개변수 TKey, TValue 두개를 요구한다
foreach를 사용할 수 있는 일반화 클래스(IEnumerable 인터페이스 상속 등 .. pg424참고)
일반화 프로그래밍
- 특수한 개념으로부터 공통된 개념을 찾아 묶는 것을 "일반화"라고 한다
- 그 일반화하는 대상이 특이하게 데이터 형식이다
void CopyArray( int[] source, int[] target)
{
for(int i = 0; i< source.Length; i++)
target[i] = source[i];
}
CopyArray()메소드를 다음과 같이 오버로딩
void CopyArray( string[] source, string[] target)
{
for(int i = 0; i< source.Length; i++)
target[i] = source[i];
}
만약 이러한 매개변수에 입력되는 배열의 형식만 다르고 내부논리는 똑같은 31가지 버전이 필요하다면?
31가지를 모두 오버로딩하지 않고도 모든 형식을 지원하게 해주자는 아이디어를 바탕으로 만들어진 프로그래밍
패러다임이 바로 일반화 프로그래밍이다
일반화 메소드
- 일반 메소드의 선언 문법과 대부분 비슷
- 대신 일반화할 형식이 들어갈 자리에 구체적인 형식의 이름 대신 "형식 매개변수(Type Parameter)" = T 가 들어간다
한정자 반환형식 메소드이름 <형식매개변수> (매개변수_목록)
{
//
}
위에서 봤던 CopyArray()코드를 일반화 하는 예제 : 데이터형식이 사용된 부분을 T기호로 치환. T는 형식(Type)을 뜻한다
void CopyArray( T[] source, T[] target)
{
for(int i = 0; i< source.Length; i++)
target[i] = source[i];
}
하지만 T는 C#이 지원하는 데이터형식이 아니다 따라서 이 코드를 컴파일하면 에러가 나는 것도 당연하다
이 코드를 컴파일하려면 T가 구체적으로 어떤 형식인지 알려줘야 함. 형식 매개변수를 입력하는 방법은 다음과 같다
메소드 이름 뒤에 홑화살괄호 <와 >를 넣어주고 그 사이에 T를 넣으면 T는 "형식 매개변수"가 된다
그리고 CopyArray()를 호출할 때 <> 사이의 T대신 형식의 이름을 입력하면 컴파일러는 메소드의 나머지 부분에
대해서도 T를 형식 매개변수 값으로 치환한다
void CopyArray<T>( string[] source, string[] target) //메소드 이름뒤에 <T>입력
{
for(int i = 0; i< source.Length; i++)
target[i] = source[i];
}
이제 CopyArray()를 호출
int[] source = { 1, 2, 3, 4, 5 );
int[] target = new int[source.Length];
CopyArray<int>(source, target); //형식매개변수 T에 int를 대입
foreach (int element in target)
Console.WriteLine(element);
일반화 클래스
- 일반화 클래스는 (데이터 형식을) 일반화한 클래스
- 다음과 같이 선언
class 클래스이름 <형식_매개변수>
{
//
}
다음 자료구조 클래스를 보자
Array_int 와 Array_Double은 기능이 같은 클래스지만 내부적으로 사용하는 데이터 형식이 다르다
clas Array_Int
{
private int[] array;
// ...
public int GetElement(int index) {return array[index]; }
}
clas Array_Double
{
private double[] array;
// ...
public double GetElement(int index) {return array[index]; }
}
이 두 클래스는 데이터 형식만 빼고 다른 부분이 모두 같으니 일반화 가능
clas Array_Generic < T >
{
private T[] array;
// ...
public T GetElement(int index) {return array[index]; }
}
다음과 같이 사용
Array_Generic<int> intArr = new Array_Generice<int>();
Array_Generice<double> dblArr = new Array_Generice<double>();
형식 매개변수 제약시키기
일반화 메소드나 일반화 클래스가 입력받는 형식 매개변수 T는 "모든"데이터 형식을 대신할 수 있었다
이렇게 "모든" 형식에 대응할 수 있는 형식 매개변수가 필요할 때도 있지만, 종종 특정 조건을 갖춘 형식에만 대응하는
형식 매개변수가 필요할 때도 있다
where T : 기반_클래스_이름
= MyList<T> 클래스의 형식 매개변수 T에 MyClass(기반클래스)로부터 상속받는 형식이어야 할 것 이라는 제약
class MyList<T> where T: MyClass
{
//...
}
where T : struct =T는 값 형식이어야 할 것
where T : class = T는 참조 형식이어야 함
where T : new() = T는 반드시 매개변수가 없는 생성자가 있어야 한다 (기본 생성자를 가진 어떤 클래스의 객체라도
생성해줌)
되짚어보자면 기본 생성자는 명시적으로 생성자를 따로 구현하지 않는 모든 클래스가 기본생성자를 가진 클래스이다
where T : 인터페이스_이름: T는 명시한 인터페이스를 반드시 구현해야 한다. 인터페이스_이름에는 여러 개의
인터페이스를 명시할 수 도 있다
where T : U = T는 또 다른 형식 매개변수 U로부터 상속받은 클래스여야 한다
예시)
CopyArray<T>() 는 소속 클래스인 BaseArray<U>의 형식 매개변수 U로부터 T가 상속받아야 할 것을 강제하고 있다
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);
}
}
where T : U 이해안감 자세한 예제 책 참고 pg416
일반화 컬렉션
List<T>
Que<T>
Stack<T>
Dictionary<TKey, TValue>
설명할건 딱히 없고 List와 List<T>의 차이점은
List<T> 클래스는 인스턴스를 만들 때 형식 매개변수를 필요로 한다는 것과 컬렉션에 "아무" 형식의 객체나 마구
집어넣을 수 있던 ArrayList와 달리 List<T>는 형식 매개변수에 입력한 형식 외에는 입력을 허용하지 않는다
그리고 Dictionary<TKey, TValue>는 10장에서 다뤘던 HastTable의 일반화 버전
형식 매개변수 TKey, TValue 두개를 요구한다
foreach를 사용할 수 있는 일반화 클래스(IEnumerable 인터페이스 상속 등 .. pg424참고)