Detect if a generic type is open?
Asked Answered
S

2

11

I have a bunch of regular, closed and opened types in my assembly. I have a query that I'm trying to rule out the open types from it

class Foo { } // a regular type
class Bar<T, U> { } // an open type
class Moo : Bar<int, string> { } // a closed type

var types = Assembly.GetExecutingAssembly().GetTypes().Where(t => ???);
types.Foreach(t => ConsoleWriteLine(t.Name)); // should *not* output "Bar`2"

Upon debugging the generic arguments of an open type, I found that their FullName is null (as well as other things like the DeclaringMethod) - So this could be one way:

    bool IsOpenType(Type type)
    {
        if (!type.IsGenericType)
            return false;
        var args = type.GetGenericArguments();
        return args[0].FullName == null;
    }

    Console.WriteLine(IsOpenType(typeof(Bar<,>)));            // true
    Console.WriteLine(IsOpenType(typeof(Bar<int, string>)));  // false

Is there a built-in way to know if a type is open? if not, is there a better way to do it? Thanks.

Syrup answered 12/9, 2014 at 15:14 Comment(5)
Did you look at the documentation for IsGenericType? Use the ContainsGenericParameters property to determine whether a Type object represents an open constructed type or a closed constructed type.Firenew
You need to get all types that are open type?...var types = Assembly.GetExecutingAssembly().GetTypes().Where(t => !t.IsGenericTypeDefinition);Blackington
@Dark Falcon: Thanks for your input. This works too. I've seen ContainsGenericParameters pop in the intellisense but I thought it returns true if there are any generic arguments for the type. Doesn't seem so reading the doc - seems that 'argument' is not the same as 'parameter'? @Blackington no, the opposite, filter them out :)Syrup
in my edited comment it will filter them out...Blackington
@Blackington noticed that, thank you +1 :)Syrup
H
25

You could use IsGenericTypeDefinition:

typeof(Bar<,>).IsGenericTypeDefinition // true
typeof(Bar<int, string>).IsGenericTypeDefinition // false
Hysterectomy answered 12/9, 2014 at 15:19 Comment(4)
"You can accept an answer in 2 minutes..." ~____~ *continues bashing left clickSyrup
Just found this, seems to be another way too IsConstructedGenericType msdn.microsoft.com/en-us/library/…Syrup
@vexe: That looks like it'll work too. Although it looks like its the exact opposite of IsGenericTypeDefinition.Hysterectomy
The .net reference source shows that if you are to close an open generic type by calling MakeGenericMethod, you must check that the type has IsGenericTypeDefinition true. So if you use the flag on MethodInfo, you should also be conforming to the expectations from .NET what constitute an open or a closed generic type. github.com/microsoft/referencesource/blob/master/mscorlib/…Hoyle
N
11

Type.IsGenericTypeDefinition is not technically the correct property to rule out open types. It will however work just fine in your case (and indeed in most other cases).

That being said, a type can be open without being a generic type definition. In the more general case, e.g. in a public method that accepts a Type parameter, what you really want is Type.ContainsGenericParameters.

For full details see the answer to this question:
Difference between Type.IsGenericTypeDefinition and Type.ContainsGenericParameters

TL;DR: The latter is recursive, while the former is not, and can thus be "fooled" by constructing a generic type that has a generic type definition as at least one of its generic type parameters.

Negate answered 4/6, 2017 at 10:7 Comment(1)
I'm not sure why yours is not the accepted answer. The question is clearly asking whether or not a type is open. Since those "half-open" types can't be instantiated they definitely can't be considered closed. Anyway for this answer +1 :)Intellection

© 2022 - 2024 — McMap. All rights reserved.