일반화 프로그래밍이란
특수한 개념으로부터 공통된 개념을 찾아 묶는것을 일반화라고하는데, 일반화프로그래밍에서 일반화하는 대상은 데이터형식이다.
void CopyArray( int[] source , int[] target)
{
for( int i = 0; i < source.Length; i++)
target[i] = source[i];
}
int형 배열을 복사하는 CopyArray메소드 에서 만약 문자열을 복사하는 메소드가 필요할때 , 일반화 프로그래밍을 모른다면
void CopyArray( string[] source , string[] target)
{
for( int i = 0; i < source.Length; i++)
target[i] = source[i];
}
이런식으로 메소드를 오버로딩해야한다. 하지만 일반화프로그래밍을 알고있다면, 이 메소드는 내부 논리는 같고 매개변수로 입력되는 배열의 형식만 다를뿐이기 때문에, 오버로딩하지않고도 모든 형식을 지원할 수 있다.
일반화 메소드의 선언
한정자 반환형식 메소드이름 <형식매개 변수> ( 매개 변수 목록)
{
//
}
ex)
void CopyArray<T> ( T[] source , T[] target)
{
for( int i =0; i < source.Length; i++)
target[i] = source [i];
}
일반화 클래스의 선언
일반화 클래스는 데이터형식을 일반화한 클래스이다.
class 클래스이름 < 형식매개변수>
{
//
}
ex)
class Array_Int
{
private int[] array;
//
public int GetElement (int index) { return array[index]; }
}
class Array_Double
{
private double[] array
//
public double GetElement( int index) { return array[index]};
}
두 클래스는 똑같은 기능을 하는 클래스이지만, 내부적으로 사용하는 데이터의 형식이 다르기때문에, 두개의 클래스로 분리해 작성하였다.
이때에 일반화 클래스를 사용하면 간단하게 개선 가능하다.
class Array<T>
{
private T[] array;
//
public T GetElement ( int index) { return array[index]; }
}
객체 생성시에는 이렇게 사용한다.
Array<int> array1 = new Array<int>();
Array<double> array2 = new Array<double>();
형식 매개 변수 제약시키기
형식매개변수 T는 모든 데이터형식을 대신할수 있다. 형식매개변수의 조건에 제약을 주면, 특정 조건의 데이터형식만 사용 가능하게 만들 수 있다.
헤더에 where 절을 추가하여 형식매개변수를 선언할 수 있다.
where 형식매개변수 : 제약조건
ex)
T가 Myclass에서 상속받은 형식이어야할때
class MyList<T> where T : Myclass
{
//
}
T가 값형식이어야할때
void CopyArray<T>( T[] source , T[] target ) where T : struct
{
for ( int i = 0; i < source.Length; i++)
target[i] = source[i]
}
제약조건 정리
where T : struct - T는 값 형식이어야한다.
where T : class - T는 참조 형식이어야 한다.
where T : new() - T는 반드시 매개변수가 없는 생성자가 있어야한다
where T : 기반클래스이름 - T는 명시한 기반 클래스의 파생클래스이거나 기반클래스와 같아야한다,
where T : 인터페이스 이름 - T는 명시한 인터페이스를 반드시 구현해야한다. 인터페이스 이름에는 여러개의 인터페이스를 명시할 수도 있다.
where T : U - T는 또 다른 형식 매개 변수 U 로부터 상속받은 클래스여야한다.
ex)
where T : 기반클래스이름
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>();
list.array[0] = new Parent();
list.array[1] = new Children();
Console.WriteLine(list.array[0].name);
Console.WriteLine(list.array[1].name);
}
}
where T : new()
public static T CreateInstance<T>() where T : new()
{
return new T();
}
// CreateInstance<T>() 메소드는 기본 생성자를 가진 어떤 클래스의 객체라도 생성가능. 기본생성자가 없다면 컴파일에러
where T : U
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);
}
}
일반화 컬렉션
ArrayList , Queue , Stack , Hashtable 이 컬렉션들은 모두 object 형식을 기반으로 했다. 따라서 모두 object 형식으로 형식변환이 가능하다. object형식을 기반으로 하기때문에 태생적으로 성능문제를 안고있는데, 일반화 컬렉션은 이 object 형식의 컬렉션이 갖고있던 문제들을 말끔히 해결한다. 일반화 컬렉션은 일반화에 기반해서 만들어져있기때문에 컴파일시 컬렉션에서 사용할 형식이 결정되고, 쓸데없는 형식변환을 일으키지 않는다.// 성능저하가 해결된다
대표적인 일반화컬렉션은 List<T> , Queue<T> , Stack<T> , Dictionary<TKey,TValue> 이 있다.
List<T>
List<T>는 ArrayList와 같은 기능을 하고, 사용법 역시 동일하지만, List<T>는 아무 형식의 객체를 마구 집어 넣을 수 있었던 ArrayList와 달리 형식매개변수로 입력한 형식 외에는 입력을 허용하지 않는다.
ex)
List<int> list = new List<int>();
List.Add(0) = 1;
List.Add(1) = 2;
List.Add(2) = 3;
List.RemoveAt(1); // 1번에있는 데이터를 지움
List.Insert(1,2); // 1번에 int형식의 2 데이터를 넣음
Queue<T>
Queue<T> 는 Queue와 같은 기능을 하고, 사용법이 동일하다. 형식매개변수를 요구한다는 점만 다르다.
ex)
Queue<int> queue = new Queue<int>();
queue.Enqueue(1);
queue.Enqueue(2);
queue.Enqueue(3);
int a = queue.Dequeue(); // a에는 1 저장
int b = queue.Dequeue(); // b에는 2 저장
Stack<T>
Stack<T> 는 Stack와 같은 기능을 하고, 사용법이 동일하다. 형식매개변수를 요구한다는 점만 다르다.
ex)
Stack<int> stack = new Stack<int>();
stack.Push(1);
stack.Push(2);
stack.Push(3);
int a = stack.Pop(); // a에는 3 저장
int b = stack.Pop(); // b에는 2 저장
Dictionary<TKey,TValue>
Dictionary<TKey,TValue> 는 Hashtable의 일반화 버전이다.
ex)
Dictionary<string, string> dic = new Dictionary<string,string>();
dic["하나"] = "one";
dic["둘"] = "two";
dic["셋"] = "three";
Console.WriteLine(dic["하나"]); // one 출력
foreach를 사용할 수 있는 일반화 클래스
foreach가 사용가능한 객체를 만들기위해서는 클래스가 IEnumerable 인터페이스와 IEnumerator 인터페이스를 상속하고, 이들의 메소드와 프로퍼티를 구현해야하는데 일반화 클래스에서 이 인터페이스를 구현하게되면 기껏 일반화 해서 얻은 성능향상을 저해하게된다. 하지만 IEnumerable<T>인터페이스와 IEnumerator 인터페이스를 상속하게되면, 성능저하없이 foreach 가 사용 가능한 일반화 클래스를 만들 수 있다.
IEnumerator <T>의 메소드 및 프로퍼티
IEnumerator GetEnumerator() IEnumerator 형식의 객체를 반환
IEnumerator<T> GetEnumerator() IEnumerator<T> 형식의 객체를 반환 // 두개 모두 구현해야한다
IEnumerable <T>의 메소드 및 프로퍼티
boolean MoveNext() 다음 요소로 이동. 컬렉션의 끝을 지난 경우에는 false, 이동이 성공한 경우에는 true를 반환한다
void Reset() 컬렉션의 첫번째 위치 "앞"으로 이동한다.
Object Current{ get;} 컬렉션의 현재 요소를 반환한다
T Current{ get; } 컬렉션의 현재 요소를 반환한다
'C#언어 > 뇌자극C#5.0' 카테고리의 다른 글
C# : Chapter - 12 델리게이트와 이벤트 (0) | 2018.01.28 |
---|---|
C# : Chapter - 11 예외 처리하기 (0) | 2018.01.26 |
C# : Chapter -9 배열 , 컬렉션 , 인덱서 (0) | 2018.01.12 |
C# : Chapter -8 프로퍼티 (0) | 2018.01.08 |
C# : Chapter -7 인터페이스 (0) | 2017.12.16 |