2022. 1. 28. 00:00ㆍCSharp/Advance
리플렉션의 관점에서 제네릭 형식과 일반 형식 간 차이점
- 형식 매개 변수(제네릭 형식 정의인 경우) 의 집합과 연결되어 있다.
- 형식 인수(생성된 형식인 경우)의 집합과 연결되어 있다
리플렉션을 사용하여 Type 의 instance 에서 알 수 없는 형식을 검사할때는 IsGenericType 속성을 사용한다.
리플렉션을 사용하여 MethodInfo 의 instance 에서 알 수 없는 메소드를 검사할때는 IsGenericMethod 속성을 사용한다.
Type 개체가 제네릭 형식인지 알기 위해서 IsGenericTypeDefinition 을 사용한다.
Type.ContainsGenericParameters 속성이 true 라면 설정되지 않는 Type 이 Generic class 에 존재 한다는 것이다. 이말은 Reflection 을 통해 GenericType 을 생성할때 아직 Type 을 지정하지 않은 parameter 가 있다는 것이므로 이럴경우 generic instance 를 생성할 수 없다.
Dictionary<TKey,TValue> 에서 TKey 를 지정하고 TValue 를 지정하지 않은 상태일 수 있다는 것이다.
Dictionary<string, TValue> 이런식
Method.ContainsGenericParameters 도 같은 형태이다.
GenericType 또는 GenericMethod 를 reflection 으로 instance 를 생성해서 실행하기 위해서는 폐쇄형(parameter 가 실제형식이 지정되어야 한다. ) 이되어야 한다.
public class MyStack<T>
{
T[] items = { };
int index;
public virtual U GenericMethod<U>(T item) where U:T
{
return (U)item;
}
public float Method(float item)
{
return item;
}
public T GetItem(int index) => items[index];
public void AddItem(T item)=> items = items.Append(item).ToArray();
}
public class MyStack
{
object[] items;
int index;
}
// 폐쇄형 class
public class IntMyStack<T> : MyStack<int>
{
public override U GenericMethod<U>(int item)
{
return base.GenericMethod<U>(item);
}
public virtual T TParamterMethod(T item)
{
return item;
}
}
public class Test : ITest
{
public void Run()
{
MyStack<float> genericStack = new MyStack<float>();
MyStack stack = new MyStack();
IntMyStack<float> intMyStack = new IntMyStack<float>();
Console.WriteLine($"genericStack is generic type == {genericStack.GetType().IsGenericType}");
Console.WriteLine($"stack is generic type == {stack.GetType().IsGenericType}");
//foreach (var method in typeof(MyStack<>).GetMethods())
foreach (var method in genericStack.GetType().GetMethods())
Console.WriteLine($"{method.Name} is generic method == {method.IsGenericMethod}, is open generic method == {method.ContainsGenericParameters}");
Console.WriteLine($"typeof(IntMyStack<>) is opened generic type == {typeof(IntMyStack<>).ContainsGenericParameters}");
Console.WriteLine($"intMyStack is opened generic type == {intMyStack.GetType().ContainsGenericParameters}");
// 이것은 IntMyStack<> 이라는 type 에대한 비교 이므로 완전 폐쇄형이 아니다.
// 그러므로 아래 intMyStack 이라는 instance 와 method 에 대한 ContainsGenericParameters 값이 다르다.
//foreach (var method in typeof(IntMyStack<>).GetMethods())
foreach (var method in intMyStack.GetType().GetMethods())
Console.WriteLine($"{method.Name} is opened generic method == {method.ContainsGenericParameters}");
var myStackType = typeof(MyStack<>);
var type_MyStack_Float =myStackType.MakeGenericType(typeof(float));
var instance = Activator.CreateInstance(type_MyStack_Float);
(instance as MyStack<float>).AddItem(12.3f);
Console.WriteLine((instance as MyStack<float>).GetItem(0));
}
}
intMyStack 같은 경우는 IntMyStack<float> 라는 형식을 지정 하여
IntMyStack<float> intMyStack = new IntMyStack<float>();
IntMyStack<T> 의 T = float
MyStack<int> 상속하며 형식을 지정하여
public class IntMyStack<T> : MyStack<int>
MyStack 의 T = int
그러므로 intMyStack 은 폐쇄형 (모든 Type 이 지정되었다. int, float) 이다.
그러므로 intMyStack.GetType() 와 typeof(IntMyStack<>) 의 TParameterMethod 의 ContainsGenericParameters 값이 다르다.
typeof(IntMyStack<>).GetMethods().TParameterMethod 의 ContainsGenericParameters 값은 true 이다.
intMyStack.GetType().GetMethods().TParameterMethod 의 ContainsGenericParameters 값은 false 이다.
MakeGeneric 를 통해 instance 를 생성하는 부분은 아래 코드 이다.
var myStackType = typeof(MyStack<>);
var type_MyStack_Float =myStackType.MakeGenericType(typeof(float));
var instance = Activator.CreateInstance(type_MyStack_Float);
(instance as MyStack<float>).AddItem(12.3f);
Console.WriteLine((instance as MyStack<float>).GetItem(0));
관련영상
'CSharp > Advance' 카테고리의 다른 글
LINQ 제한 연산자 (Where) (0) | 2022.02.01 |
---|---|
LINQ 란 (0) | 2022.01.31 |
제네릭 대리자 (Generic Delegate) (0) | 2022.01.27 |
제네릭 메서드 (Generic Method) (0) | 2022.01.26 |
제네릭 클래스 (Generic class) (0) | 2022.01.25 |