检测一个通用类型是否是开放的?

9

我在我的程序集中有许多常规、封闭和公开类型。我有一个查询,试图从中排除公开类型。

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"

当我调试一个开放类型的通用参数时,我发现它们的FullName是空的(以及其他的一些东西,比如DeclaringMethod)- 所以这可能是一种方式:
    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

有没有内置的方法可以知道一个类型是否是开放的?如果没有,有更好的方式吗?谢谢。


1
你有查看过IsGenericType的文档吗?使用ContainsGenericParameters属性来确定一个Type对象是表示开放构造类型还是封闭构造类型。 - Dark Falcon
1
你需要获取所有的公开类型吗?... 变量 types = Assembly.GetExecutingAssembly().GetTypes().Where(t => !t.IsGenericTypeDefinition); - terrybozzio
@Dark Falcon:感谢您的贡献。这个也可以。我在智能感知中看到过 ContainsGenericParameters,但我认为它会在类型中有任何泛型参数时返回 true。阅读文档似乎并非如此 - 看起来 'argument' 不同于 'parameter'?@terrybozzio 不是,相反,要将它们过滤掉 :) - vexe
在我的编辑评论中,它会将它们过滤掉... - terrybozzio
@terrybozzio注意到了,谢谢+1 :) - vexe
2个回答

23

你可以使用IsGenericTypeDefinition

typeof(Bar<,>).IsGenericTypeDefinition // true
typeof(Bar<int, string>).IsGenericTypeDefinition // false

1
你可以在2分钟内接受一个答案... ____ *继续猛击左键 - vexe
@vexe:哈哈,很高兴能帮忙。 - Andrew Whitaker
刚刚发现这个,似乎还有另一种方式:IsConstructedGenericType http://msdn.microsoft.com/en-us/library/system.type.isconstructedgenerictype%28v=vs.110%29.aspx - vexe
@vexe:这看起来也能行。虽然它看起来正好与IsGenericTypeDefinition相反。 - Andrew Whitaker
.NET参考源代码显示,如果要通过调用MakeGenericMethod来关闭一个开放的泛型类型,您必须检查该类型的IsGenericTypeDefinition属性是否为true。因此,如果您在MethodInfo上使用该标志,您还应符合.NET对于何种情况构成开放或闭合泛型类型的预期要求。 https://github.com/microsoft/referencesource/blob/master/mscorlib/system/reflection/methodinfo.cs - Tore Aurstad

11

Type.IsGenericTypeDefinition 不是技术上正确的属性来排除开放类型,但在您的情况下(以及大多数其他情况下)它却可以正常使用。

话虽如此,一个类型可以是开放的而不是泛型类型定义。在更一般的情况下,例如:在接受 Type 参数的公共方法中,您真正想要的是Type.ContainsGenericParameters

有关详细信息,请参见此问题的答案:
Type.IsGenericTypeDefinition 和 Type.ContainsGenericParameters 的区别

简而言之:后者是递归的,而前者不是,并且因此可以“欺骗”,即构造一个具有泛型类型定义作为其泛型类型参数之一的泛型类型。


1
我不确定为什么你的回答没有被采纳。问题显然是在询问一个类型是否是开放的。由于那些“半开放”类型不能被实例化,它们肯定不能被认为是封闭的。无论如何,对于这个答案+1 :) - Riki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接