[Mono-list] Base class casting weirdness

Dan Lewis dihlewis@yahoo.co.uk
17 Jan 2002 23:52:04 +0000


Thanks, Mark! You're right - that's exactly what it was. The wording in
the C# reference manual is a little confusing when talking about the
((A)this).I equivalence, and appears to be very similar to that used in
the Java language specification when discussing its "super" operator -
Java's behaviour is exactly the same as this.

I found a book on Java which said there was no way to access a virtual
method in A from a second derivative class C using the 'super' keyword,
so I'm guessing the same could be said for C# using the 'base' operator.
I don't know whether this is by design or by neglect.

Dan.

On Thu, 2002-01-17 at 05:51, Mark Hurley wrote:
> 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 
> 
> 
> _______________________________________________
> Mono-list maillist  -  Mono-list@ximian.com
> http://lists.ximian.com/mailman/listinfo/mono-list



_________________________________________________________
Do You Yahoo!?
Get your free @yahoo.com address at http://mail.yahoo.com