开发者

Call base class member functions from subclass members

开发者 https://www.devze.com 2023-03-27 08:32 出处:网络
public class A { ... public virtual void PrintMe() { /* do A */ } } public class B : A { ... public override void PrintMe() { /* do B *开发者_运维技巧/ }
public class A
{
    ...
    public virtual void PrintMe() { /* do A */ }
}

public class B : A
{
    ...
    public override void PrintMe() { /* do B *开发者_运维技巧/ }
}

public class C : B
{
    ...
    public override void PrintMe() { /* do C */ }

    private void Fun()
    {
        // call C::PrintMe - part one
        PrintMe();

        // call B::PrintMe - part two
        base.PrintMe();

        // call A::PrintMe - part three
        ???
    }
}
  1. Is the code of part two correct?

  2. How to call A::PrintMe inside C::Fun?


Your question 1 will work as expected, it will do B.PrintMe()

Your question 2 is not quite so simple. There is no implicit or explicit way to execute A.PrintMe().

The only way I can think to achieve your goal is with the addition of a protected method on A which can be called from C.

public class A
{
    protected void BasePrintMe() { Console.WriteLine("A"); }
    public virtual void PrintMe() { BasePrintMe(); }
}

public class B : A { public override void PrintMe() { Console.WriteLine("B"); } }

public class C : B
{
    public override void PrintMe() { Console.WriteLine("C"); }

    public void FunA()
    {
        // call C::PrintMe - part one
        PrintMe();

        // call B::PrintMe - part two
        base.PrintMe();

        // call A
        this.BasePrintMe();

    }

}

output:

C
B
A


If you want this desired functionality, you can call base.PrintMe() in your B class.

public class B : A
{
    public override void PrintMe()
    { 
     /* do B */
     base.PrintMe();
    }
}

Otherwise, you can't call the implementation from class A without resorting to something hackish.


You could add a method to each class that would do a base.PrintMe(). In A, this method would do nothing as it has no base class.

   public class A
   {
      public virtual void PrintMe()
      {
         Debug.WriteLine( "PrintMe: A" );
      }

      public virtual void PrintMyBase()
      {
      }
   }

   public class B : A
   {
      public override void PrintMe()
      {
         Debug.WriteLine( "PrintMe: B" );
      }

      public override void PrintMyBase()
      {
         base.PrintMe();
      }
   }

   public class C : B
   {
      public override void PrintMe()
      {
         Debug.WriteLine( "PrintMe: C" );
      }

      public override void PrintMyBase()
      {
         base.PrintMe();
      }

      private void Fun()
      {
         // call C::PrintMe - part one
         PrintMe();

         // call B::PrintMe - part two
         PrintMyBase();

         // call A::PrintMe - part three
         base.PrintMyBase();
      }
   }

The befit here is that no class has to know anything more than it's base class and we can control what's exposed down the inheritance chain.

Hope this helps


There's no language-supported way of doing this, which is a handy hint to suggest that you shouldn't do it.

If you find yourself needing this in real-world code then you should really try to re-think your design.

Anyway, to answer the question, you can do this using reflection and some custom IL-generation, like so:

private void Fun()
{
    // call C::PrintMe - part one
    PrintMe();

    // call B::PrintMe - part two
    base.PrintMe();

    // call A::PrintMe - part three
    MethodInfo mi = this.GetType().GetMethod("PrintMe").GetBaseDefinition();

    var dm = new DynamicMethod("dm", null, new[] { typeof(object) }, this.GetType());

    ILGenerator il = dm.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Call, mi);    // use call rather than callvirt
    il.Emit(OpCodes.Ret);

    var action = (Action<object>)dm.CreateDelegate(typeof(Action<object>));
    action(this);
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号