일반화 프로그래밍이란


특수한 개념으로부터 공통된 개념을 찾아 묶는것을 일반화라고하는데, 일반화프로그래밍에서 일반화하는 대상은 데이터형식이다. 


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; } 컬렉션의 현재 요소를 반환한다




+ Recent posts