I cannot figure out how to use MethodImpl's to override a virtual method
when I have multiple levels of inheritance using MethodImpl's. Let's
start with a simple C# example:

internal class Base {
     public override string ToString () { return "Base"; }
}

internal class Derived : Base {
     public override string ToString () { return "Derived"; }
}

internal class MoreDerived : Derived {
     public override string ToString () { return "MoreDerived"; }
}

internal class App {
    static void Main () {
       MoreDerived m = new MoreDerived ();
       Derived     d = m;
       Base        b = m;
       object      o = m;

       System.Console.WriteLine ("Object.ToString() returns " +
o.ToString());
       System.Console.WriteLine ("Base.ToString() returns " +
b.ToString());
       System.Console.WriteLine ("Derived.ToString() returns " +
d.ToString());
       System.Console.WriteLine ("MoreDerived.ToString() returns " +
m.ToString());
    }
}

Given the above class hierarchy, running the program produces the
following expected output:

Object.ToString() returns MoreDerived
Base.ToString() returns MoreDerived
Derived.ToString() returns MoreDerived
MoreDerived.ToString() returns MoreDerived

Now, let's rename the Base.ToString method to Base.Foo but still have it
override System.Object.ToString. A quick ILDASM, a change to the Base
class and reassemble:

.class private auto ansi beforefieldinit Base
       extends [mscorlib]System.Object
{
  .method public hidebysig virtual instance string 
          Foo() cil managed
  {
    <snip>

  } // end of method Base::ToString

  .override [mscorlib]System.Object::ToString with instance string
Base::Foo()

<snip>

} // end of class Base

I run the modified program and get the same, expected output:

Object.ToString() returns MoreDerived
Base.ToString() returns MoreDerived
Derived.ToString() returns MoreDerived
MoreDerived.ToString() returns MoreDerived


Now, the problem I cannot seem to solve: I now want to modify the
Derived class so that it has a method called 'Bar' that overrides
Base.ToString. Of course, Base.ToString doesn't really exist, but
Base.Foo exists and it's its implementation I really want to override.
So I change the definition of Derived like so:

.class private auto ansi beforefieldinit Derived
       extends Base
{
  .method public hidebysig virtual instance string 
          Bar() cil managed
  {
    <snip>
  } // end of method Derived::ToString

  .override Base::Foo with instance string Derived::Bar()

<snip>

} // end of class Derived

Now the program won't load due to a TypeLoadException:

Unhandled Exception: System.TypeLoadException: Method Foo on type
Derived from assembly Foo is overriding a method impl.
   at App.Main()

(Yes, the error message itself is a little wrong but that's an unrelated
problem.) So I figure conceptually I want to override Base.ToString so I
changed the .override to:

  .override Base::ToString with instance string Derived::Bar()

But I still get the same exception:

Unhandled Exception: System.TypeLoadException: Method Foo on type
Derived from assembly Foo is overriding a method impl.
   at App.Main()

So finally, I changed the .override to:

  .override [mscorlib]System.Object::ToString with instance string
Derived::Bar()

Now the program loads and runs but the output isn't what I expected or
want:

Object.ToString() returns MoreDerived
Base.ToString() returns Base
Derived.ToString() returns MoreDerived
MoreDerived.ToString() returns MoreDerived

Basically, the question becomes how can I make Derived::Bar use the same
vtbl slot as Base::Foo which itself is using the same vtbl slot as
System.Object::ToString?

-- Brent Rector, .NET Wise Owl
Demeanor for .NET - an obfuscation utility
http://www.wiseowl.com/Products/Products.aspx

You can read messages from the DOTNET archive, unsubscribe from DOTNET, or
subscribe to other DevelopMentor lists at http://discuss.develop.com.

Reply via email to