通用嵌套类型中的typeof(T)

时间:2014-01-16 19:31:53

标签: c# generics typeof type-parameter

我不明白为什么以下行为完全按照它的方式行事。我甚至不知道它是由隐藏还是其他原因造成的。

class A<T>
{

    public class B : A<int>
    {
        public void b()
        {
            Console.WriteLine(typeof(T).ToString());
        }
        public class C : B
        {
            public void c()
            {
                Console.WriteLine(typeof(T).ToString());
            }
        }
        public class D : A<T>.B
        {
            public void d()
            {
                Console.WriteLine(typeof(T).ToString());
            }
        }
    }
}
class Program
{
    static void Main(string[] args)
    {
        A<string>.B.C c = new A<string>.B.C();
        A<string>.B.D d = new A<string>.B.D();
        c.c();
        c.b();
        d.d();
        d.b();
    }
}

问题是:

  1. 为什么c.c()生成System.String而c.b()生成System.Int32

  2. 为什么d.d()d.b()都会生成System.String而行为与C类的行为完全相同?

3 个答案:

答案 0 :(得分:11)

这是我多年前在我的博客上发布的一个谜题的变体:

http://blogs.msdn.com/b/ericlippert/archive/2007/07/27/an-inheritance-puzzle-part-one.aspx

和Cyrus之前在他的博客上发布了:

http://blogs.msdn.com/b/cyrusn/archive/2005/08/01/446431.aspx

请参阅那里的讨论以获取详细信息。

简要说明Bclass C : B中的含义是什么?检查容器class B。它是否包含任何名为B的类型?不。然后检查容器的基类。容器的基类是A<int>。它是否包含任何名为B的内容?是。所以这意味着class C : A<int>.B

现在我们说cA<string>.B.C。我们称之为方法A<string>.B.C.c() T中的A<string>是什么?显然是string。因此c.c()String打印T

现在我们致电A<string>.B.C.b(),但A<string>.B.C中没有这样的方法。它在哪里获得这种方法?从它的基础类。什么是基类? A<int>.B。所以我们打电话给A<int>.B.b()。整个T的{​​{1}}是什么?显然是A<int>

现在我们来int。基类是无关紧要的。 A<string>.B.D.d() T string A<string>

最后A<string>.B.D.b()A<string>.B.D上没有这样的方法,所以必须从它的基类型中获取它。 T string在整个A<string>中都是A<string>.B,因此基本类型为A<string>.B.b()。因此,这会调用class A_string { public class B : A_int { public void b() { Console.WriteLine(typeof(string).ToString()); } public class C : A_int.B // Note! { public void c() { Console.WriteLine(typeof(string).ToString()); } } public class D : A_string.B { public void d() { Console.WriteLine(typeof(string).ToString()); } } } }

如果这对你没有意义,请拼出一切。让我们用String代替T:

class A_int
{
    public class B : A_int
    {
        public void b()
        {
            Console.WriteLine(typeof(int).ToString());
        }
        public class C : A_int.B // Note!
        {
            public void c()
            {
                Console.WriteLine(typeof(int).ToString());
            }
        }
        public class D : A_int.B
        {
            public void d()
            {
                Console.WriteLine(typeof(int).ToString());
            }
        }
    }
}

好的,这是其中一种类型。现在让我们对int执行相同的操作:

A_string.B.C.c()

现在给出这些类型,应该清楚显示A_string.B.C.b(),{{1}}等所有内容。

答案 1 :(得分:3)

A<string>.B.C继承A<int>.B,因为基类声明中的B首先来自内部父作用域。 (澄清一下,其父作用域为A<T>.B,其中包含一个名为B的类型,引用A<int>.B,继承自其基类A<int>

调用b()来自其基类,其中T(来自父作用域)为int

D使用A<T>.B从最外层范围(T)明确继承A<T>,因此其T始终来自A<> in它的类型名称。

答案 2 :(得分:3)

这是Eric Lippert在this blog article中描述的谜题的一个稍微复杂的例子,然后在this article中进行了解释。

简短摘要(我强烈建议阅读本文)是在这种情况下,行C : B中存在歧义。需要做出关于B在这种情况下实际意味着什么的决定;是A<T>.B还是A<int>.B。基本上,编译器选择后者,给出规范中描述的“更好”的特定标准。