[Mono-list] Base class casting weirdness
Mark Hurley
debian4tux@telocity.com
Thu, 17 Jan 2002 00:51:42 -0500
On Thu, Jan 17, 2002 at 01:13:11AM +0000, Daniel Lewis wrote:
> Hi,
>
> I wonder if anyone can shed light on this. In C#, the 'base' keyword is
> used to access methods and constructors of base classes:
>
> class A {
> public virtual string Foo () { return "A"; }
> }
>
> class B : A {
> public override string Foo () { return base.Foo (); }
> }
>
> Invoking Foo on an instance of B returns "A", as you'd expect. The C#
> programmer's reference that is packaged with the SDK states that:
>
> base.Foo ()
>
> .. called in an instance method of B is exactly equivalent to writing:
>
> ((A)this).Foo ()
>
I have reason to believe this SDK doc is wrong. Invoking Foo thru the
"base" [base.Foo()] disables the virtual invocation on A, and treats
the base method [Foo()] as a non-virtual method.
[((A)this).Foo ()] has the same runtime type of [B.Foo ()]. This
causes your StackOverflowexception, because B continues to recursively
invoke itself, not the Foo in A because the one in A is virtual.
This is considered normal behavior, and I read thru two books and the
MSDN before I found this. :) whew!
If you "hide" B.Foo with something like:
new private string Foo () {}
...then C can still override A, and you can access A via the
base-access [base.].
> And that in fact this is what the compiler replaces it with at compile
> time. But if you try to implement it this way:
Here is sample IL code the compiler generates:
For:
public override string Foo () { return base.Foo (); }
We have this call:
IL_0001: call instance string ConsoleApplication2.A::Foo()
And for this:
public override string Foo () { return ((A)this).Foo(); }
we end up with:
IL_0001: callvirt instance string ConsoleApplication2.A::Foo()
note the difference between [call] and [callvirt]. The latter is used
to call virtual methods and interface methods, while [call] is used to
call static and nonvirtual methods.
>
> public override string Foo () { return ((A)this).Foo (); }
>
> CSC will compile it, but you'll get a StackOverflowException at runtime.
> Why would I want to write it this way instead of using 'base'? Well, I've
> got a class C derived from B, that wants to implement Foo by invoking A's
> definition. Can anyone think of a way to do this? Is the runtime
> exception correct, or is this an SDK bug? And what does MCS/Mono do with
> this?
Mark Hurley