简体   繁体   中英

Get all types that are used as generic type arguments

Is it possible to get all types that are used as generic type arguments within certain assembly?

Basically, imagine I have this class:

public class Foo<T>
{
    T SomeProperty {get; set;}
}

Now, I have an application and there I use the above in some way:

var stringFoo = new Foo<string>();
var intFoo = new Foo<int>();

Assume this is the only place the Foo is used. Now I would like to get type definitions of Foo<string> and Foo<int> . Ie I want to find all types that are constructed from generic type definition ( Foo<T> ) within given assembly.

Is that even possible?

Correction... Still a pain... But no extra libraries needed. Now... On top of my head there are various places where you could find a type Foo<> :

  • attributes ( [MyAttribute(typeof(Foo<>)] , or perhaps Foo<> is in itself an Attribute )

  • base type chain ( class MyClass : Foo<int> ) or if Foo<> is a IFoo<> then implemented interfaces

  • members of a type (fields, properties, events, methods) (here I mean only the signature part of those, so the field type, the method arguments and return type...)

  • inner types of a type (types defined inside another type)

All of these can be found with "simple" application of reflection.

On top of these you can take a look at local variables of methods/properties (they are methods in the end), events (even they are methods in the end): if you have a MethodInfo method , you can get a MethodBody body = method.GetMethodBody() , and the MethodBody defines a LocalVariables .

Note that without disassembling the code (for example with Mono.Cecil ) you won't be able to detect that in

public class C
{
    public List<int> MyList;

    public void M()
    {
        MyList = new List<int>();
        Console.WriteLine(new List<int>());
    }
}

the method M uses a List<int>() , because no local variable of type List<int> is used. So in the end you'll need to even disassemble all the methods.

Clearly each time you find a type, you must check if the type is a Foo<> , a subclass of Foo<> , or perhaps uses Foo<> as a parameter ( List<Foo<>> ), or is a pointer Foo<>* , or a managed pointer ref Foo<> or...)

As far as variables is concerned, you could discover the types by examining the method.

public static void GetGenericVariables()
{
    //Declaring two variables here that use Foo<>
    var inttype = new Foo<int>();
    var stringType = new Foo<string>();

    var methodInfo = typeof(ClassContainingMethod).GetMethod("GetGenericVariables");
    var variables = methodInfo.GetMethodBody().LocalVariables;
    foreach (var variable in variables)
    {
        if (variable.LocalType.IsGenericType && variable.LocalType.GetGenericTypeDefinition() == typeof(Foo<>))
        {
            Console.WriteLine(variable.LocalType.GenericTypeArguments[0].FullName);
        }
    }
}

Output:

System.Int32

System.String

You would have to recurse over the assemblies and types though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM