Search code examples
c#classinheritance

Is there a method to use base.base in an override method?


This might be bad practice, but I'd still like to know if it's possible.

public class BaseClass
{
  protected virtual void createArrays(int vertexCount)
  {
    // do the actual work
  }
}

public class A : BaseClass
{
  protected override void createArrays(int vertexCount)
  {
       // Do something specific to A
       base.createArrays(vertexCount);
  }
}

public class B : A 
{
  protected override void createArrays(int vertexCount)
  {
    //Do something specific to B, but not to A
    base.base.createArrays(vertexCount); // this is the part that doesn't work, I actually want to call the createArrays from the BaseClass
  }
}

It's probably best to inherit both A and B from BaseClass, but I'd appreciate some insights


Solution

  • No, this is not allowed at all.

    ECMA-334, the C# spec, says:

    12.8.15

    At binding-time, base_access expressions of the form base.I and base[E] are evaluated exactly as if they were written ((B)this).I and ((B)this)[E], where B is the base class of the class or struct in which the construct occurs. Thus, base.I and base[E] correspond to this.I and this[E], except this is viewed as an instance of the base class.

    Note: Unlike this, base is not an expression in itself. It is a keyword only used in the context of a base_access or a constructor_initializer (§15.11.2). end note


    Having said that, a straight reading of ECMA-335, the .NET CLI spec, seems to imply that this would be allowed, by using a call (as opposed to callvirt) instruction on that method, as long as it's done as usual through an instance of the same type:

    Partition III Section 3.19

    When using the call opcode to call a non-final virtual method on an instance other than a boxed value type, verification checks that the instance reference to the method being called is the result of ldarg.s 0, ldarg 0 or ldarg.0 and the caller's body does not contain starg.s 0, starg 0 or ldarga.s 0, ldarga 0.

    [Rationale: This means that non-virtually calling a non-final virtual method is only verifiable in the case where the subclass methods calls one of its superclasses using the same this object reference, where same is easy to verify. This means that an override implementation effectively "hides" the superclass' implementation, and can assume that the override implementation cannot be bypassed by code outside the class hierarchy.

    For non-sealed class hierarchies, malicious code can attempt to extend the class hierarchy in an attempt to bypass a class' override implementation. However, this can only be done on an object of the malicious type, and not of the class with the override, which mitigates much of the security concern. end rationale]

    I haven't tried it though, and it's possible that this would be considered non-verifiable code by most verifiers. It should at least work, as it's definitely correct (in the sense the IL will compile).