블로그 이미지
다비도프

만나고, 고백하고, 가슴 떨리고, 설레이고, 웃고, 사랑하고, 키스하고, 함께하고..

Rss feed Tistory
WEB/ASP.NET With C# 2007. 4. 2. 13:53

[MSDN] Generic

개요
제네릭은 2.0 버전의 C# 언어와 CLR(공용 언어 런타임)에 새로 도입된 기능입니다.
제네릭을 통해 .NET Framework에 형식 매개 변수라는 개념이 처음 소개되었습니다.
형식 매개 변수를 사용하면 클라이언트 코드에서 클래스나 메서드를 선언하고 인스턴스화할 때까지
하나 이상의 형식 지정을 연기하는 클래스와 메서드를 디자인할 수 있습니다.
예를 들어, 다음과 같이 제네릭 형식 매개 변수 T를 사용하면 런타임 캐스트나 boxing 작업에 따른 비용이나
위험을 초래하지 않은 채 다른 클라이언트 코드에서 사용 가능한 단일 클래스를 작성할 수 있습니다.

// Declare the generic class
public class GenericList<T>
{
    void Add(T input) { }
}
class TestGenericList
{
    private class ExampleClass { }
    static void Main()
    {
        // Declare a list of type int
        GenericList<int> list1 = new GenericList<int>();
        // Declare a list of type string
        GenericList<string> list2 = new GenericList<string>();
        // Declare a list of type ExampleClass
        GenericList<ExampleClass> list3 = new GenericList<ExampleClass>();
    }
}
이전 방식의 문제점
모든 참조나 값 형식은 Object에 암시적으로 업캐스팅됩니다. 항목이 값 형식이면 이를 목록에 추가할 때 boxing해야 하고 이를 검색할 때 unboxing해야 합니다. 캐스팅이나 boxing 및 unboxing 작업은 모두 성능을 저하시킵니다. 큰 컬렉션을 반복해야 하는 시나리오에서는 boxing과 unboxing의 영향을 결코 무시할 수 없습니다.
컴파일 타임에 형식을 검사할 수 없다는 점을 들 수 있습니다.


형식 매개 변수 명명 지침

  • 필수적 단일 문자 이름으로도 자체 설명이 가능하여 설명적인 이름을 굳이 사용할 필요가 없는 경우가 아니면 제네릭 형식 매개 변수 이름을 설명적인 이름으로 지정하십시오.
  • 선택적 단일 문자 형식 매개 변수를 사용하는 형식에는 형식 매개 변수 이름으로 T를 사용하십시오.
  • 필수적 설명적인 형식 매개 변수 이름 앞에 “T”를 붙이십시오.
  • 선택적 매개 변수 이름 안에서 형식 매개 변수에 적용되는 제약 조건을 나타내십시오. 예를 들어 ISession으로 제한되는 매개 변수의 이름은 TSession이 될 수 있습니다.


형식 매개 변수에 대한 제약 조건

제약 조건은 where 컨텍스트 키워드를 사용하여 지정합니다. 다음 표에서는 여섯 가지의 형식 제약 조건을 보여 줍니다.



바인딩되지 않은 형식 매개 변수

공용 클래스 SampleClass<T>{}의 T와 같이 제약 조건이 없는 형식 매개 변수를 바인딩되지 않은 형식 매개 변수라고 합니다. 바인딩되지 않은 형식 매개 변수에는 다음과 같은 규칙이 적용됩니다.

  • != 및 == 연산자를 사용할 수 없습니다. 구체적인 형식 인수에서 이러한 연산자를 지원하리라는 보장이 없기 때문입니다.
  • 바인딩되지 않은 형식 매개 변수와 System.Object 사이에 변환하거나 이 매개 변수를 임의의 인터페이스 형식으로 명시적으로 변환할 수 있습니다.
  • 바인딩되지 않은 형식 매개 변수를 null과 비교할 수 있습니다. 바인딩되지 않은 매개 변수를 null과 비교하는 경우 형식 인수가 값 형식이면 비교 결과로 항상 false가 반환됩니다.

런타임의 제네릭

값 형식을 매개 변수로 사용한 제네릭 형식
처음 생성할 때 런타임에서는 MSIL의 해당 위치를 제공된 매개 변수로 대체하여 특수화된 제네릭 형식을 만듭니다. 고유한 값 형식이 매개 변수로 사용될 때마다 특수화된 제네릭 형식이 만들어집니다.
예를 들어 프로그램 코드에서 다음과 같이 정수로 구성된 스택을 선언한다고 가정합니다.
Stack<int> stack;

이 시점에서 런타임은 매개 변수를 정수로 적절히 대체하여 특수화된 버전의 Stack<T> 클래스를 생성합니다. 이제부터 프로그램에서 정수 스택을 사용하면 런타임은 생성된 특수화 Stack<T> 클래스를 다시 사용합니다.

그러나 프로그램의 다른 지점에서 매개 변수로 long 또는 사용자 정의 구조체를 사용하는 다른 Stack<T> 클래스가 만들어지면, 런타임에서는 MSIL의 해당 위치를 long으로 대체하여 다른 버전의 제네릭 형식을 생성합니다. 특수화된 각 제네릭 클래스에는 내부적으로 값 형식이 포함되므로 변환은 더 이상 필요하지 않습니다.

참조 형식을 매개 변수로 사용한 제네릭 형식
처음 생성될 때 런타임에서는 MSIL의 매개 변수를 개체 참조로 대체하여 특수화된 제네릭 형식을 만듭니다. 이후 참조 형식에 관계없이 참조 형식을 매개 변수로 사용하여 생성된 형식이 인스턴스화될 때마다 런타임에서는 이전에 만든 특수화된 버전의 제네릭 형식을 다시 사용합니다. 이는 모든 참조의 크기가 동일하기 때문에 가능합니다.
Stack<Customer> customers;
이 시점에서 런타임은 데이터를 저장하는 대신 이후에 채워질 개체 참조를 저장하는 특수화된 버전의 Stack<T> 클래스를 생성합니다. 하지만 다른 참조 형식의 스택을 만들어질 경우 값 형식과는 달리, Order 형식에 대한 또 다른 특수화된 버전의 Stack<T> 클래스는 만들어지지 않습니다. 대신 특수화된 버전의 Stack<T> 클래스 인스턴스가 만들어지고 orders 변수가 이 인스턴스를 참조하도록 설정됩니다.
,
TOTAL TODAY