Making member virtual prevents calling default interface implementation and causes StackOverflowException in C# 8

后端 未结 3 1234
不知归路
不知归路 2021-01-13 03:02

Consider the code:

class ChildClass : BaseClass {

    public void Method1() {} //some other method

}

abstract class         


        
3条回答
  •  星月不相逢
    2021-01-13 03:36

    For the sake of future readers...

    While the accepted answer provided by @Panagiotis is correct, in that there is no difference whether virtual modifier is present or not and StackOverflowExcpetion will occur in any case, I wanted to provide a concrete answer to the question that I settled on.

    The whole point of implementing DoWork() in the IChildInterface as opposed to in a class was for code reuse and staying "DRY". Classes that implement IChildInterface should however be able to add their own functionality on top of what's provided by IChildInterface.

    And therein lies a problem, as calling ((IChildInterface)this).DoWork(); from any class (abstract or not) that implements IChildInterface will result in infinite recursion. The only reasonable way out seems to use protected static members (as in fact is suggested in the Microsoft Docs):

    class ChildClass : BaseClass {
    
        public void Method1() {} //some other method
    
    }
    
    abstract class BaseClass : IChildInterface {
    
        public virtual void DoWork() {
         // Base class specific implementation here
    
         // Then call into default implementation provided by IChildInterface:
         // Instead of this: ((IChildInterface)this).DoWork();
         // Use static implementation:
         IChildInterface.DoWork(this);
        }
    
    }
    
    interface IChildInterface : IBaseInterface {
    
        protected static void DoWork(IChildInterface it){
          // Implementation that works on instance 'it'
        }
        void IBaseInterface.DoWork() => IChildInterface.DoWork(this);
    
    }
    
    interface IBaseInterface {
    
        void DoWork();
    
    }
    

    In the above solution we are staying "DRY" by still having a single (core) implementation of DoWork(), but it is located in a protected static member of the interface IChildInterface instead of being part of its inheritance hierarchy.

    Then, as far as the inheritance hierarchy is concerned, all interfaces / classes deriving from / implementing IChildInterface could simply use IChildInterface.DoWork(this) to access the default implementation. This applies to the IChildInterface itself.

提交回复
热议问题