I don't understand why the following behaves the way it does at all. I don't even know if it's caused by hiding or something else.
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();
}
}
The questions are:
Why does cc()
produce System.String while cb()
produces System.Int32
?
Why does dd()
and db()
both produce System.String
and not behave in exactly the same way as the class C
?
This is a variation of a puzzle that I posted on my blog many years ago:
http://blogs.msdn.com/b/ericlippert/archive/2007/07/27/an-inheritance-puzzle-part-one.aspx
and Cyrus posted on his blog before that:
http://blogs.msdn.com/b/cyrusn/archive/2005/08/01/446431.aspx
See the discussion there for details.
Briefly: what does B
mean in class C : B
? Check the container, class B
. Does it contain any type called B
? No. Then check the container's base class. The container's base class is A<int>
. Does it contain anything called B
? Yes. So this means class C : A<int>.B
.
Now we say that c
is A<string>.BC
. We call method A<string>.BCc()
What is T
throughout A<string>
? Obviously string
. So cc()
prints String
for T
.
Now we call A<string>.BCb()
but there is no such method in A<string>.BC
directly. Where does it get this method? From its base class. What's it's base class? A<int>.B
. So we call A<int>.Bb()
. What is T
throughout A<int>
? Obviously int
.
Now we come to A<string>.BDd()
. The base class is irrelevant. T
is string
throughout A<string>
.
And finally A<string>.BDb()
. There is no such method on A<string>.BD
directly so it must get it from its base type. T
is string
throughout A<string>
, so the base type is A<string>.B
. Therefore this calls A<string>.Bb()
.
If that doesn't make sense to you, spell everything out. Let's substitute String for T:
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());
}
}
}
}
OK, that's one of the types. Now let's do the same for int:
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());
}
}
}
}
Now given those types it should be clear what A_string.BCc()
, A_string.BCb()
, etc, all print out.
A<string>.BC
inherits A<int>.B
, because B
in the base class declaration comes from the inside parent scope first. (to clarify, its parent scope is A<T>.B
, which contains a type named B
referring to A<int>.B
, inherited from its base class A<int>
)
Calling b()
comes from its base class, in which T
(from the parent scope) is int
.
D
explicitly inherits A<T>.B
, using T
from the outermost scope ( A<T>
), so its T
always comes from A<>
in its typename.
This is a very slightly more complex example of a puzzle Eric Lippert describes in this blog article , which is then explained in this article .
The short summary (I highly suggest just reading the article) is that in this case there is an ambiguity in the line C : B
. A decision needs to be made as to what B
actually means in this context; whether it's A<T>.B
or A<int>.B
. Essentially, the compiler chooses the latter, given a particular criteria of "betterness" described in the spec.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.