Can someone explain to me why the below code outputs what it does? Why is T a String in the first one, not an Int32, and why is it the opposite case in the next output?
Can someone explain to me why the below code outputs what it does?
I'll explain briefly here; a longer explanation can be found here.
The crux of the matter is determining the meaning of B
in class C : B
. Consider a version without generics: (for brevity I'll omit the publics.)
class D { class E {} }
class J {
class E {}
class K : D {
E e; // Fully qualify this type
}
}
That could be J.E
or D.E
; which is it? The rule in C# when resolving a name is to look at the base class hierarchy, and only if that fails, then look at your container. K already has a member E by inheritance, so it does not need to look at its container to discover that its container has a member E by containment.
But we see that the puzzle has this same structure; it's just obfuscated by the generics. We can treat the generic like a template and just write out the constructions of A-of-string and A-of-int as classes:
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
}
}
And now it should be clear why A_of_string.B.M()
writes string
but A_of_string.B.C.M()
writes int
.