Search code examples
c#oopstaticvirtualabstract

c# enforcing specific method signature in derived classes (abstract virtual static)


I have an abstract class BaseClass and want to enforce that all class Derived: BaseClass have to override a method foo resulting in a very specific signature. The Problem is as following:

  1. Classes which inherit from BaseClass have to implement foo on their own (pref. only if they are not abstract) [like abstract]
  2. BaseClass must have a base-implementation, derived classes can call [like virtual]
  3. [Signature of foo in derived classes should be static (the classes themself are not!) [eddit: omitted]]
  4. Arguments of foo are of class Derived/this.GetType() (pref. without changing signature of BaseClass)

It is already hard enough/ impossible(?) to combine two of these (exept 4.), but maybe there are some clever workarounds and I take what I can get. At last here is some pseudo code to better reflect my intention:

public abstract class BaseClass
{
    bool baseBool;
    public abstract virtual static bool foo(BaseClass b1, BaseClass b2)
    {
        //sample code
        return b1.baseBool ^ b2.baseBool;
    }
}

public class Derived: BaseClass
{
    bool derivedBool;
    public static override bool foo(Derived d1, Derived d2)
    {
        //sample code
        return base.foo(d1, d2) && d1.derivedBool ^ d2.derivedBool;
    }
}

Solution based on accepted answer by lidqy

public abstract class BaseClass
{
    bool baseBool;
    public abstract bool foo(BaseClass b1, BaseClass b2);
}

public abstract class BaseClassWrappedCRTP<T>: BaseClass where T: BaseClassWrappedCRTP<T>
{
    public override bool foo(BaseClass b1, BaseClass b2)
    {
        //sample code
        return b1.baseBool ^ b2.baseBool && fooWrappedCRTP((T)b1, (T)b2);
    }

    protected abstract bool fooWrappedCRTP(T d1, T d2);
}

public class Derived: BaseClassWrappedCRTP<Derived>
{
    bool derivedBool;
    protected override bool fooWrappedCRTP(Derived d1, Derived d2)
    {
        //sample code
        return d1.derivedBool ^ d2.derivedBool;
    }
}

Note that if Derived were abstract class Derived: BaseClassWrappedCRTP<Derived>, we would need abstract class DerivedWrappedCRTP<T>: Derived where T: DerivedWrappedCRTP<T> to continue inheritance of foo in this way (Given an actual need to access non-generic Derived).


Solution

  • As mentioned in the comments inheritance and staticness don't fit.
    From what you told I think this code might match your use case...

    //declare the mixed lists with List<IBase> to get rid of the type params
    interface IBase {
       bool foo(BaseClass b1, BaseClass b2);
    } 
    
    public abstract class BaseClass<T> : IBase where T : BaseClass
    {
        bool baseBool;
        //If you call Foo from a "mixed list" use non generic, base class parameters, else you get casting troubles enumerating and calling 'foo'
        public bool foo(BaseClass b1, BaseClass b2)
        {
            //sample code
            return b1.baseBool ^ b2.baseBool && fooOverride((T)b1, (T)b2);
        }
        protected abstract bool fooOverride(T b1, T b2);
    
    }
    
    public class Derived : BaseClass<Derived>
    {
        bool derivedBool;
        protected override bool fooOverride(Derived d1, Derived d2)
        {
            //sample code
            return d1.derivedBool ^ d2.derivedBool;
        }
    }