2016-12-25 142 views
4

有人可以向我解释为什么下面的代码输出它的作用? 为什么T是第一个字符串,而不是Int32,为什么它在下一个输出中是相反的情况?继承和泛型类型设置

这让人不解的是从interview with Eric Lippert

当我看到通过代码,我真的不知道,如果它的将是一个Int32或String:

public class A<T> 
    { 
     public class B : A<int> 
     { 
      public void M() { System.Console.WriteLine(typeof(T)); } 
      public class C : B { } 
     } 
    } 

    public class P 
    { 
     public static void Main() 
     {    
      (new A<string>.B()).M(); //Outputs System.String 
      (new A<string>.B.C()).M(); //Outputs System.Int32 
      Console.Read(); 
     } 
    } 
+1

https://blogs.msdn.microsoft.com/ericlippert/2007/07/30/an-inheritance-puzzle-part-two/ –

回答

2

更改代码略:

public class A<T> 
{ 
    public class B : A<int> 
    { 
     public void M() { System.Console.WriteLine(typeof(T)); } 
     public class C : A<T>.B { } 
    } 
} 

public class P 
{ 
    public static void Main() 
    {    
     (new A<string>.B.C()).M(); //Outputs System.String 
    } 
} 

注意我是如何改变C的基类BA<T>.B。这将输出从System.Int32更改为System.String

没有这个,A<string>.B.C不是从A<string>.B得到的,而是从A<int>.B得出的,导致你看到的行为。这是因为一般来说,基类中定义的名称可以通过非限定查找来获得,名称B在基类A<int>中定义。

+0

如果说一个班级如果距离它不超过一个“等级”就可以访问输入的T值,这是真的吗?例如。 (new A .B())。M();输出字符串,因为B直接访问A 这意味着提供的T覆盖了B默认从其继承的值? (new A .B.C())。M();输出Int32,因为一旦在C中,它离输入的String的T值有2级距离,因此它使用默认的Int32继承值。 –

+0

@Backwards_Dave不,事实并非如此,将'M'的定义放入'C'中会显示它不是真的。 'A .B.M'打印'T',无论你打电话时多远有多远。棘手的部分只是由于误导性的基类,'A .B.M'被调用而不是'A .B.M'。 – hvd

+0

让我试着再解释一遍。如果T向下流过继承,它将覆盖继承中定义的任何默认T值。但是,只要有“向上”流,在这种情况下,当C调用C的父类中定义的M()时,指定的T值将丢失,并使用Int32的默认T值。而如果M()以C而不是B来声明,那么就不会有向上流动。不完全确定在这里使用什么词,也许“流”不是很好,但我希望你知道我的意思。 –

4

方法MB打印typeof(T)A<T>AB的父级。

因此,不管B来自何处,M打印typeof(T)String

所以A<T>.B.M打印最接近AT

所以A<string>.B.M将打印string

现在,让我们拓展表达A<string>.B.C,这相当于A<string>.B.A<int>.B(因为CA<int>.B),所以方法A<string>.B.A<int>.B.M将打印最近T

A<string>.B.A<int>.B.M将打印int

+0

为什么C等于A .B?更确切地说,为什么String的输入值T会丢失,并使用Int的默认值? –

+0

这不等于,它是如何解析类型的类型解析替代类型。 –

3

Introduction to Generics T也是在嵌套类可用。类别B的情况是嵌套在A中。另一方面,C嵌套为B,并且B的T可用于C。如您所见,B的T为int,并且调用C的方法将使用int作为通用参数。

3

方法M()始终打印父类的类的泛型参数的类型:

所以(new A<string>.B.C()).M();应打印泛型类型的B这始终是int。 (你可以看到B总是A<int>

而且(new A<string>.B()).M();应打印string因为BA<string>

+0

我不确定如果我没有看到输出,我可以乍一看正确的输出,但看到结果后,检测结果如何打印并不难。 Chu难题很容易解决巡逻;) –

3

有人可以向我解释为什么下面的代码输出它做什么?

问题的症结在于确定Bclass C : B中的含义。考虑没有泛型版本:(为简便起见,我会忽略了公众。)

class D { class E {} } 
class J { 
    class E {} 
    class K : D { 
    E e; // Fully qualify this type 
    } 
} 

这可能是J.ED.E;这是什么?解决名称时,C#中的规则是查看基类层次结构,只有在失败时才查看容器。 K通过继承已经有了一个成员E,所以它不需要看它的容器,通过遏制来发现它的容器有一个成员E.

但我们看到拼图有相同的结构;它只是泛型的混淆。我们可以把一般的像一个模板,只是写出来的A-的字符串的结构和A-的-INT作为类:

class A_of_int 
{ 
    class B : A_of_int 
    { 
    void M() { Write("int"); } 
    class C : B { } // A_of_int.B 
    } 
} 
class A_of_string 
{ 
    class B : A_of_int 
    { 
    void M() { Write("string"); } 
    class C : B {} // still A_of_int.B 
    } 
} 

现在应该很清楚为什么A_of_string.B.M()写道:stringA_of_string.B.C.M()写道:int