C#:泛型类中的嵌套类是否应该被认为是通用的?

时间:2009-01-28 08:44:19

标签: c# generics reflection

namespace GenericsTest
{
    public class AGenericClass<T>
    {
        public class NestedNonGenericClass
        {
        }
    }
}

在上面的示例中,NestedNonGenericClass应该被视为通用类吗?

反射API说它是一个泛型类,甚至把包含类的模板参数作为嵌套类的模板参数。

Type nestedClass = typeof(AGenericClass<int>.NestedNonGenericClass);
Console.Out.WriteLine("IsGeneric: {0}\tHasGenericArguments: {1}", 
   nestedClass.IsGenericType, nestedClass.GetGenericArguments().Length > 0);

打印出来:

  

IsGeneric:True HasGenericArguments:   真

我不完全同意这种行为。即使编译器为NestedNonGenericClass生成泛型类型,我也想知道它是否是通用的,因为它是声明的,或者因为它的容器是通用的。

所以,我的问题是:

首先,您是否认为可以考虑嵌套类通用,因为它的容器是通用的?为什么/为什么不呢?

其次,您是否碰巧知道其他一些API可以帮助我只识别声明为通用的类?

P.S:我在ECMA规范中找不到与此相关的任何内容(或者我可能只是掩饰了它)。

- 编辑 -

要添加更多上下文,我正在开发一种代码生成器。我正在使用反射API来确定类型是否是通用的。

我遇到了Dictionary<TKey, TValue>.KeyCollection的问题。

对于KeyCollection,反射API表示它是通用的,并将我交给容器中声明的TKeyTValue。因此,生成器最终会生成Dictionary<TKey, TValue>.KeyCollection<Tkey, TValue>

我能解决这个问题的唯一方法是将嵌套类的模板参数与容器匹配,并消除所有匹配的参数。但我想知道是否有更好的方法。

4 个答案:

答案 0 :(得分:19)

简而言之,是的 - 一个类型从包含它的任何类型继承类型参数:这是List<T>.Enumerator和许多其他场景等的关键 - 它们共享{{1来自外部类(不只是任何T)。

ECMA ref是§25.1:

  

任何嵌套在泛型内的类   类声明或通用结构   声明(第25.2节)本身就是一个   泛型类声明,因为类型   包含类型的参数   应提供以创建一个   构造类型。

答案 1 :(得分:6)

是的,您的嵌套类绝对是通用的,因为T绑定到嵌套类的任何实例范围内的类型(这被称为封闭泛型)。

using System;
using System.Collections.Generic;

public class AGenericClass<T> {
    public class NestedNonGenericClass {
        public void DoSomething() {
            Console.WriteLine("typeof(T) == " + typeof(T));
        }
    }
}

public class MyClass {
    public static void Main()   {
        var c = new AGenericClass<int>.NestedNonGenericClass();
        var d = new AGenericClass<DateTime>.NestedNonGenericClass();
        c.DoSomething();
        d.DoSomething();
        Console.ReadKey(false); 
    }

}

相同的DoSomething()方法产生不同的输出,具体取决于泛型类型的关闭方式 - 所以是的,内部类肯定表现出通用行为。

答案 2 :(得分:2)

如果您不打算在NestedNonGenericClass中使用T,您可以将它放在类之外并将其设置为私有..那么它就不会是Generic ....

答案 3 :(得分:2)

我选择理解它的方式是,当您使用泛型类型时,C#会生成该类型的所有内容。实际上,如果我想象一下如果我使用上面例子中的AGenericClass和AGenericClass会产生什么,那么你最终会得到两个嵌套类的副本:

public class AGenericClass<int>
{
    public class NestedNonGenericClass
    {
    }
}

public class AGenericClass<float>
{
    public class NestedNonGenericClass
    {
    }
}

因此,我认为嵌套类是泛型类,因为它有两个版本,一个叫做AGenericClass&lt; int&gt; .NestedNonGenericClass,另一个叫做AGenericClass&lt; float&gt; .NestedNonGenericClass。实际上,就像你明确指定嵌套类也是通用类一样。如果您希望嵌套类适应泛型类型,则此行为非常有用。

但是,我发现我不能再以与普通类相同的方式使用嵌套类了。我不记得确切的例子了,我很抱歉,但是我知道,一旦我不得不将一个类移出一个泛型,以便我可以按照预期从代码中的其他地方使用它。它违背了我一直用于嵌套类的常用模式,因此我不喜欢它,但这是唯一的方法。所以我可以理解你是否可能不同意这样做的方式,但说实话,我认为它的方式是最清晰的方式。我的意思是,对于您和编译器来说,如果您将嵌套类移到外部并将其作为常规类,那么您不希望编译器将其生成为泛型。我不认为他们可以改善这一点。