Generic Class 에 대해 part 2 - Type parameters 및 약간 더

밑에 올린 일반적인 Generic Class에 이은 두번쨰 Type parameter에 대한 요약입니다.

Type Parameter

일단 Type parameter 자체는 나중에 Type Argument로 대체되는 place holder 이상의 의미는 없습니다만, 그래도 Type Parameter에 대한 몇가지 제약 사항이 있습니다. 밑에 그 제약 사항을 나열했습니다.

  • Type parameter 이름은 unique 해야 합니다. type parameter가 정의된 클러스 내에서 class, method, 다른 type parameter등과 같은 이름을 사용할수 없습니다.
     class GenericClass<GenericName, GenericName /* Error */>    {
        public void GenericName /* Error */()
        {
        }
    }
  • type parameter의 scope는 class ClassName 이후 '<' 의 부분 부터, class의 정의가 끝나는 '}' 까지 입니다.
     class GenericClass<T /* T is valid from here */>
    {
        T _genericVariable;

        public void Method(T genericInput)
        {
            _genericVariable = genericInput;
        }

        /* to here */
    }
  • type parameter 자체가 base class나 interface의 이름이 될수 없습니다.
     class GenericClass<T> : T /* Error */
    {
    }
  • type parameter로 부터 method를 부르기 위해선 type parameter가 그 method를 implement 한다는것을 constraint를 통해 알려주어야 합니다.
     class GenericClassError<T>
    {
        T _internalData;

        public int CompareTo(T rhs)
        {
            return _internalData.CompareTo(rhs); // Error
        }
    }

    class GenericClassOk<T> where T : IComparable
    {
        T _internalData;

        public int CompareTo(T rhs)
        {
            return _internalData.CompareTo(rhs); // OK
        }
    }
  • 가능한한 type parameter의 implicit conversion은 제공된 constraint에 따릅니다. 보다 자세한 내용은 나중에 따로 올리도록 하겠습니다.
     class GenericClassError
    {
        T _internalData;

        public IDataAdapter GetDataAdapter()
        {
            return _internalData; // Error
        }
    }

    class GenericClassOK where T : IDataAdapter
    {
        T _internalData;

        public IDataAdapter GetDataAdapter()
        {
            return _internalData; // OK
        }
    }
  • 특별한 경우를 제외 하고는 T t = null 처럼 쓸수 없습니다.
    • type parameter T가 실제 어떤 type argument (value type, reference type)로 대체 될지 알수 없기 때문에 t = null (only valid for reference type or nullable value type) 같은 구문은 사용할수 없습니다.
    • 만약 reference type 만이 T 타입으로 쓸수 있도록 제약하시면 t=null을 쓰실수 있습니다.
    • 비록 명시적으로 t = null 이라고 쓰실수 없지만, default 키워드를 이용하셔서 reference 타입에만 null로 초기화 하는것은 (t = default(t)) 가능합니다.
    • t == null이나 t != null 같은 건 당근 쓰실수 있습니다.
     class GenericClassError<T>
    {
        T _internalData;

        public GenericClassError()
        {
            _internalData = default(T); // Okay

            _internalData = null; // Error
        }
    }

    class GenericClassOK<T> where T : class
    {
        T _internalData;

        public GenericClassOK()
        {
            _internalData = null; // Okay
        }
    }
  • T t = new T() 와 같은 구문은 where T : new() 처럼 constructor-constraint 를 지정할 때만 가능합니다.
     class GenericClassError<T>
    {
        T _internalData;

        public GenericClassError()
        {
            _internalData = new T(); // Error
        }
    }

    class GenericClassOK<T> where T : new()
    {
        T _internalData;

        public GenericClassOK()
        {
            _internalData = new T(); // Okay
        }
    }
  • type parameter는 attribute에 사용 될수 없습니다
    // Error! An attribute that references a generic type parameter will cause a compile time error
   //[MyAttribute(MyOtherType = typeof(Bar<int, T2, string>))] // error!

   // OK. An attribute can reference an open generic type
   [MyAttribute(MyOtherType = typeof(Bar<>))]

   // OK. An attribute can reference a closed constructed generic type
   [MyAttribute(MyOtherType = typeof(Bar<int, double, string>))]
   public class Foo<T1, T2>
   {
   }
  • class StaticClass { public static int Get() {..} } 이고 class A<T> where T : StaticClass 라고 했다고 해서 T.Get() 처럼 type paramter 자체를 이용해서 static 함수를 부를수 없습니다.
     class StaticClass
    {
        static public void CallStaticMethod()
        {
        }
    }

    class GenericClass<T> where T : StaticClass
    {
        public void CallStatic()
        {
            T.CallStaticMethod(); // Error
        }
    }
  • type parameter는 언제나 managed type으로 사용되야 합니다.
  • 실제 runtime에서는 open construct type은 존재 하지 않습니다. open construct type은 컴파일 타입에만 존재 하고 실제 런타임에서는 closed construct type만이 존재 합니다.

이상이 Generic Class의 Type Parameter에 대한 대략 적인 룰입니다.

Instance Type

모든 타입은 실제 런타임에 이용되는 instance type이 있습니다. 쉽게 말해 런타임에 this 변수의 타입을 말합니다. 일반적인 class의 경우 그 class의 instance type은 그 class 자체 입니다. - class D -> instance type 'D'

Generic class의 경우 instance type이 class<type parameter>입니다 - class genericClass<T> -> instance type genericClass<T>

Base Specification

Generic class의 base class 를 지정할때 역시 몇가지 제약 사항이 있습니다.

  • class extend<V> : V { ... } - type parameter 자체를 base class 혹은 interface로 쓰는거 안됩니다.
  • class extend<V> : baseclass<B> { .. } - class 정의 부분의 type parameter list에 선언 되지 않은 type parameter를 base class의 type parameter로 제공 할수 없습니다.
  • class extend<V> : baseClass<V> { ... } - 이렇게 class 정의 부분에 선언된 type parameter를 base class의 type parameter로 제공하는것은 가능합니다.
  • class extend<V> : bassClass<int> {...} - generic class의 base class로써 closed generic class를 사용하는것은 언제나 가능합니다.

....

이상 여기 까지..