내보내기(0) 인쇄
모두 확장
이 문서는 기계로 번역한 것입니다. 원본 텍스트를 보려면 포인터를 문서의 문장 위로 올리십시오. 추가 정보
번역
원본
이 항목은 아직 평가되지 않았습니다.- 이 항목 평가

방법: 리플렉션을 사용하여 제네릭 형식 검사 및 인스턴스화

제네릭 형식에 대한 정보는 다른 형식에 대한 정보와 같이, 제네릭 형식을 나타내는 Type 개체를 검사하여 얻습니다. 가장 큰 차이점은 제네릭 형식에는 해당 제네릭 형식 매개 변수를 나타내는 일련의 Type 개체가 있다는 것입니다. 이 단원의 첫 번째 절차에서는 제네릭 형식을 검사합니다.

제네릭 형식 정의의 형식 매개 변수에 형식 인수를 바인딩하여 생성된 형식을 나타내는 Type 개체를 만들 수 있습니다. 두 번째 절차에서는 이 작업에 대해 설명합니다.

제네릭 형식과 해당 형식 매개 변수를 검사하려면

  1. 제네릭 형식을 나타내는 Type의 인스턴스를 가져옵니다. 다음 코드에서는 C# typeof 연산자(Visual Basic의 경우 GetType, Visual C++의 경우 typeid)를 사용하여 형식을 가져옵니다. Type 개체를 가져오는 다른 방법은 Type 클래스 항목을 참조하십시오. 이 절차의 나머지 부분에는 t라는 메서드 매개 변수에 형식이 포함되어 있습니다.

    
    Type d1 = typeof(Dictionary<,>);
    
    
    
  2. 형식이 제네릭인지 여부를 확인하려면 IsGenericType 속성을 사용하고 형식이 제네릭 형식 정의인지 여부를 확인하려면 IsGenericTypeDefinition 속성을 사용합니다.

    
    Console.WriteLine("   Is this a generic type? {0}",
        t.IsGenericType);
    Console.WriteLine("   Is this a generic type definition? {0}",
        t.IsGenericTypeDefinition);
    
    
    
  3. GetGenericArguments 메서드를 사용하여 제네릭 형식 인수가 포함된 배열을 가져옵니다.

    
    Type[] typeParameters = t.GetGenericArguments();
    
    
    
  4. 각 형식 인수에 대해 IsGenericParameter 속성을 사용하여 해당 인수가 형식 매개 변수(예를 들어, 제네릭 형식 정의에 있음)인지 또는 형식 매개 변수에 대해 지정된 형식(예를 들어, 생성된 형식에 있음)인지 여부를 확인합니다.

    
    Console.WriteLine("   List {0} type arguments:", 
        typeParameters.Length);
    foreach( Type tParam in typeParameters )
    {
        if (tParam.IsGenericParameter)
        {
            DisplayGenericParameter(tParam);
        }
        else
        {
            Console.WriteLine("      Type argument: {0}",
                tParam);
        }
    }
    
    
    
  5. 형식 시스템의 경우 제네릭 형식 매개 변수는 일반 형식과 같이 Type의 인스턴스로 표시됩니다. 다음 코드에서는 제네릭 형식 매개 변수를 나타내는 Type 개체의 이름과 매개 변수 위치를 표시합니다. 매개 변수 위치는 여기에서는 그다지 중요하지 않지만 다른 제네릭 형식의 형식 인수로 사용된 형식 매개 변수를 검사할 때 보다 중요합니다.

    
    private static void DisplayGenericParameter(Type tp)
    {
        Console.WriteLine("      Type parameter: {0} position {1}", 
            tp.Name, tp.GenericParameterPosition);
    
    
    
  6. GetGenericParameterConstraints 메서드를 사용하여 단일 배열의 모든 제약 조건을 가져옴으로써 제네릭 형식 매개 변수의 기본 형식 제약 조건과 인터페이스 제약 조건을 확인합니다. 제약 조건의 순서는 특별히 정해져 있지 않습니다.

    
    Type classConstraint = null;
    
    foreach(Type iConstraint in tp.GetGenericParameterConstraints())
    {
        if (iConstraint.IsInterface)
        {
            Console.WriteLine("         Interface constraint: {0}",
                iConstraint);
        }
    }
    
    if (classConstraint != null)
    {
        Console.WriteLine("         Base type constraint: {0}", 
            tp.BaseType);
    }
    else
        Console.WriteLine("         Base type constraint: None"); 
    
    
    
  7. 형식 매개 변수가 참조 형식이어야 하는 것과 같이 형식 매개 변수에 대한 특수 제약 조건을 확인하려면 GenericParameterAttributes 속성을 사용합니다. 이 속성에는 다음 코드와 같이 가릴 수 있는 가변성을 나타내는 값도 포함되어 있습니다.

    
    GenericParameterAttributes sConstraints = 
        tp.GenericParameterAttributes & 
        GenericParameterAttributes.SpecialConstraintMask;
    
    
    
  8. 특수 제약 조건 특성은 플래그이며 특수 제약 조건이 없음을 나타내는 동일한 플래그(GenericParameterAttributes.None)도 공 분산 또는 반공변성(Contravariance)을 나타냅니다. 그러므로 이러한 조건 중 어느 하나를 테스트하려면 적절한 마스크를 사용해야 합니다. 이 경우에는 GenericParameterAttributes.SpecialConstraintMask를 사용하여 특수 제약 조건 플래그를 격리합니다.

    
    if (sConstraints == GenericParameterAttributes.None)
    {
        Console.WriteLine("         No special constraints.");
    }
    else
    {
        if (GenericParameterAttributes.None != (sConstraints &
            GenericParameterAttributes.DefaultConstructorConstraint))
        {
            Console.WriteLine("         Must have a parameterless constructor.");
        }
        if (GenericParameterAttributes.None != (sConstraints &
            GenericParameterAttributes.ReferenceTypeConstraint))
        {
            Console.WriteLine("         Must be a reference type.");
        }
        if (GenericParameterAttributes.None != (sConstraints &
            GenericParameterAttributes.NotNullableValueTypeConstraint))
        {
            Console.WriteLine("         Must be a non-nullable value type.");
        }
    }
    
    
    

제네릭 형식은 템플릿과 같습니다. 해당 제네릭 형식 매개 변수의 실제 형식을 지정해야 해당 인스턴스를 만들 수 있습니다. 런타임에 리플렉션을 사용하여 이 작업을 수행하려면 MakeGenericType 메서드가 필요합니다.

제네릭 형식의 인스턴스를 생성하려면

  1. 제네릭 형식을 나타내는 Type 개체를 가져옵니다. 다음 코드에서는 두 가지 다른 방법으로 Dictionary<TKey, TValue> 제네릭 형식을 가져옵니다. 즉, 형식에 대해 설명하는 문자열에 Type.GetType(String) 메서드 오버로드를 사용하거나, 생성된 형식 Dictionary<String, Example>(Visual Basic의 경우 Dictionary(Of String, Example))에 대해 GetGenericTypeDefinition 메서드를 호출합니다. MakeGenericType 메서드에는 제네릭 형식 정의가 필요합니다.

    
    // Use the typeof operator to create the generic type 
    // definition directly. To specify the generic type definition,
    // omit the type arguments but retain the comma that separates
    // them.
    Type d1 = typeof(Dictionary<,>);
    
    // You can also obtain the generic type definition from a
    // constructed class. In this case, the constructed class
    // is a dictionary of Example objects, with String keys.
    Dictionary<string, Example> d2 = new Dictionary<string, Example>();
    // Get a Type object that represents the constructed type,
    // and from that get the generic type definition. The 
    // variables d1 and d4 contain the same type.
    Type d3 = d2.GetType();
    Type d4 = d3.GetGenericTypeDefinition();
    
    
    
  2. 형식 매개 변수를 대체할 형식 인수 배열을 생성합니다. 이 배열에는 올바른 수의 Type 개체가 포함되어야 하며 개체 순서는 형식 매개 변수 목록에 표시되는 순서와 동일해야 합니다. 이 경우 첫 번째 형식 매개 변수인 키의 형식은 String이며 사전의 값은 Example 클래스의 인스턴스입니다.

    
    Type[] typeArgs = {typeof(string), typeof(Example)};
    
    
    
  3. MakeGenericType 메서드를 호출하여 형식 매개 변수에 형식 인수를 바인딩하고 형식을 생성합니다.

    
    Type constructed = d1.MakeGenericType(typeArgs);
    
    
    
  4. 생성된 형식의 개체를 만들려면 CreateInstance(Type) 메서드 오버로드를 사용합니다. 다음 코드에서는 결과 Dictionary<String, Example> 개체에 Example 클래스의 두 인스턴스를 저장합니다.

    
    object o = Activator.CreateInstance(constructed);
    
    
    

다음 코드 예제에서는 DisplayGenericType 메서드를 정의하여 코드에서 사용되는 제네릭 형식 정의와 생성된 형식을 검사하고 해당 정보를 표시합니다. DisplayGenericType 메서드는 IsGenericType, IsGenericParameterGenericParameterPosition 속성과 GetGenericArguments 메서드를 사용하는 방법을 보여 줍니다.

이 예제에서는 또한 DisplayGenericParameter 메서드를 정의하여 제네릭 형식 매개 변수를 검사하고 해당 제약 조건을 표시합니다.

이 코드 예제에서는 형식 매개 변수의 제약 조건을 설명하는 제네릭 형식을 포함하여 일련의 테스트 형식을 정의하며 해당 형식에 대한 정보를 표시하는 방법을 보여 줍니다.

또한 형식 인수의 배열을 만들고 MakeGenericType 메서드를 호출하여 Dictionary<TKey, TValue> 클래스에서 형식을 생성합니다. 이 프로그램은 MakeGenericType을 사용하여 생성된 Type 개체와 typeof(Visual Basic의 경우 GetType)를 사용하여 가져온 Type 개체를 비교하여 동일한 개체임을 보여 줍니다. 또한 이와 유사하게 GetGenericTypeDefinition 메서드를 사용하여 생성된 형식의 제네릭 형식 정의를 가져오고 해당 정의와 Dictionary<TKey, TValue> 클래스를 나타내는 Type 개체를 비교합니다.


using System;
using System.Reflection;
using System.Collections.Generic;
using System.Security.Permissions;

// Define an example interface.
public interface ITestArgument {}

// Define an example base class.
public class TestBase {}

// Define a generic class with one parameter. The parameter
// has three constraints: It must inherit TestBase, it must
// implement ITestArgument, and it must have a parameterless
// constructor.
public class Test<T> where T : TestBase, ITestArgument, new() {}

// Define a class that meets the constraints on the type
// parameter of class Test.
public class TestArgument : TestBase, ITestArgument
{
    public TestArgument() {}
}

public class Example
{
    // The following method displays information about a generic
    // type.
    private static void DisplayGenericType(Type t)
    {
        Console.WriteLine("\r\n {0}", t);
        Console.WriteLine("   Is this a generic type? {0}",
            t.IsGenericType);
        Console.WriteLine("   Is this a generic type definition? {0}",
            t.IsGenericTypeDefinition);

        // Get the generic type parameters or type arguments.
        Type[] typeParameters = t.GetGenericArguments();

        Console.WriteLine("   List {0} type arguments:", 
            typeParameters.Length);
        foreach( Type tParam in typeParameters )
        {
            if (tParam.IsGenericParameter)
            {
                DisplayGenericParameter(tParam);
            }
            else
            {
                Console.WriteLine("      Type argument: {0}",
                    tParam);
            }
        }
    }

    // The following method displays information about a generic
    // type parameter. Generic type parameters are represented by
    // instances of System.Type, just like ordinary types.
    private static void DisplayGenericParameter(Type tp)
    {
        Console.WriteLine("      Type parameter: {0} position {1}", 
            tp.Name, tp.GenericParameterPosition);

        Type classConstraint = null;

        foreach(Type iConstraint in tp.GetGenericParameterConstraints())
        {
            if (iConstraint.IsInterface)
            {
                Console.WriteLine("         Interface constraint: {0}",
                    iConstraint);
            }
        }

        if (classConstraint != null)
        {
            Console.WriteLine("         Base type constraint: {0}", 
                tp.BaseType);
        }
        else
            Console.WriteLine("         Base type constraint: None"); 

        GenericParameterAttributes sConstraints = 
            tp.GenericParameterAttributes & 
            GenericParameterAttributes.SpecialConstraintMask;

        if (sConstraints == GenericParameterAttributes.None)
        {
            Console.WriteLine("         No special constraints.");
        }
        else
        {
            if (GenericParameterAttributes.None != (sConstraints &
                GenericParameterAttributes.DefaultConstructorConstraint))
            {
                Console.WriteLine("         Must have a parameterless constructor.");
            }
            if (GenericParameterAttributes.None != (sConstraints &
                GenericParameterAttributes.ReferenceTypeConstraint))
            {
                Console.WriteLine("         Must be a reference type.");
            }
            if (GenericParameterAttributes.None != (sConstraints &
                GenericParameterAttributes.NotNullableValueTypeConstraint))
            {
                Console.WriteLine("         Must be a non-nullable value type.");
            }
        }
    }

    [PermissionSetAttribute(SecurityAction.Demand, Name="FullTrust")]
    public static void Main()
    {
        // Two ways to get a Type object that represents the generic
        // type definition of the Dictionary class. 
        //
        // Use the typeof operator to create the generic type 
        // definition directly. To specify the generic type definition,
        // omit the type arguments but retain the comma that separates
        // them.
        Type d1 = typeof(Dictionary<,>);

        // You can also obtain the generic type definition from a
        // constructed class. In this case, the constructed class
        // is a dictionary of Example objects, with String keys.
        Dictionary<string, Example> d2 = new Dictionary<string, Example>();
        // Get a Type object that represents the constructed type,
        // and from that get the generic type definition. The 
        // variables d1 and d4 contain the same type.
        Type d3 = d2.GetType();
        Type d4 = d3.GetGenericTypeDefinition();

        // Display information for the generic type definition, and
        // for the constructed type Dictionary<String, Example>.
        DisplayGenericType(d1);
        DisplayGenericType(d2.GetType());

        // Construct an array of type arguments to substitute for 
        // the type parameters of the generic Dictionary class.
        // The array must contain the correct number of types, in 
        // the same order that they appear in the type parameter 
        // list of Dictionary. The key (first type parameter)
        // is of type string, and the type to be contained in the
        // dictionary is Example.
        Type[] typeArgs = {typeof(string), typeof(Example)};

        // Construct the type Dictionary<String, Example>.
        Type constructed = d1.MakeGenericType(typeArgs);

        DisplayGenericType(constructed);

        object o = Activator.CreateInstance(constructed);

        Console.WriteLine("\r\nCompare types obtained by different methods:");
        Console.WriteLine("   Are the constructed types equal? {0}",
            (d2.GetType()==constructed));
        Console.WriteLine("   Are the generic definitions equal? {0}",
            (d1==constructed.GetGenericTypeDefinition()));

        // Demonstrate the DisplayGenericType and 
        // DisplayGenericParameter methods with the Test class 
        // defined above. This shows base, interface, and special
        // constraints.
        DisplayGenericType(typeof(Test<>));
    }
}


  • 이 코드에는 컴파일에 필요한 C# using 문(Visual Basic의 경우 Imports)이 포함되어 있습니다.

  • 추가 어셈블리 참조는 필요하지 않습니다.

  • csc.exe, vbc.exe 또는 cl.exe를 사용하여 명령줄에서 코드를 컴파일합니다. Visual Studio에서 코드를 컴파일하려면 콘솔 응용 프로젝트 템플릿에 코드를 삽입합니다.

이 정보가 도움이 되었습니까?
(1500자 남음)
의견을 주셔서 감사합니다.

커뮤니티 추가 항목

추가
표시:
© 2014 Microsoft. All rights reserved.