有人可以向我解释为什么下面的代码会输出它的作用吗? 为什么T是一个字符串在第一个,而不是Int32,为什么它在下一个输出中是相反的情况?
这个谜题来自interview with Eric Lippert
当我查看代码时,我真的不知道它是否会成为Int32或字符串:
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();
}
}
答案 0 :(得分:5)
有人可以向我解释为什么以下代码会输出它的作用吗?
问题的关键在于确定<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<gradient
android:angle="270"
android:endColor="#000000"
android:startColor="#FFFFFF" />
<corners android:radius="10dp" />
<padding
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="#e95d11" />
<corners android:radius="10dp" />
<size
android:width="50dp"
android:height="50dp" />
</shape>
</item>
</layer-list>
中B
的含义。考虑一个没有泛型的版本:(为简洁起见,我将省略公众。)
class C : B
可能是class D { class E {} }
class J {
class E {}
class K : D {
E e; // Fully qualify this type
}
}
或J.E
;这是什么?解析名称时C#中的规则是查看基类层次结构,只有当它失败时,才能查看容器。 K已经通过继承拥有成员E,因此不需要查看其容器以发现其容器具有包含成员E.
但是我们看到这个拼图具有相同的结构;它只是被仿制药混淆了。我们可以像处理模板那样处理泛型,只需将A-of-string和A-of-int的结构写成类:
D.E
现在应该清楚为什么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()
但string
写A_of_string.B.C.M()
。
答案 1 :(得分:4)
M
内的方法B
打印typeof(T)
的{{1}},A<T>
是A
的父类。
因此无论B
是否来自任何内容,B
打印M
都是typeof(T)
。
因此String
会打印最接近A<T>.B.M
的{{1}}。
因此A
将打印T
现在,让我们展开表达式A<string>.B.M
,它相当于string
(因为A<string>.B.C
是A<string>.B.A<int>.B
),所以方法C
会打印最近的{ {1}}。
A<int>.B
将打印A<string>.B.A<int>.B.M
答案 2 :(得分:3)
Introduction to Generics T也可以在嵌套类中使用。类B
的情况就是这种情况,它嵌套在A
中。另一方面,C
嵌套在B
中,B
的T可用于C
。如您所见,B
的T为int
,C
上调用的方法将使用int
作为通用参数。
答案 3 :(得分:3)
方法M()
始终打印其类的父类的泛型参数的类型:
因此(new A<string>.B.C()).M();
应打印B
的通用类型,始终为int
。 (您可以看到B
始终为A<int>
)
另外(new A<string>.B()).M();
应打印string
,因为B
的父级是A<string>
。
答案 4 :(得分: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
的基类从B
更改为A<T>.B
。这会将输出从System.Int32
更改为System.String
。
如果不这样做,A<string>.B.C
不是来自A<string>.B
,而是来自A<int>.B
,导致您已经看到的行为。这是因为通常,基类中定义的名称可通过非限定查找获得,名称B
在基类A<int>
中定义。