C# virtual (or abstract) static methods

14,664

Solution 1

No, you cannot override a static method. "static" also means that it is statically bound by the compiler, so the actual method to be called is not found at runtime, but bound at compile time.

What you should do is make the class non-static. Make the method virtual and override it and make full benefit of real inheritance. Then, if you really need it, make a static entry point to a reference of your class. For instance a static factory, singleton (it's an anti-pattern in most of the cases but is as good as a static class) or just a static property.

Solution 2

You could store the TargetMethod as a delegate, which a subclass could change as needed:

class TestBase {
    protected static Action _targetMethod;

    static new() {
       _targetMethod = new Action(() => {
           Console.WriteLine("Base class");
       });
    }

    public static void TargetMethod() {
        _targetMethod();
    }

    public static void Operation() {
        TargetMethod();
    }
}

class TestChild : TestBase {
    static new() {
       _targetMethod = new Action(() => {
           Console.WriteLine("Child class");
       });
    }
}

Since these are static instances, though - the _targetMethod is shared across all instances - changing it in TestChild changes it for TestBase as well. You may or may not care about that. If you do, generics or a Dictionary<Type, Action> might help.

Overall, though, you'd have a much easier time if you didn't insist on statics, or perhaps used composition instead of inheritance.

Solution 3

If you are looking to do abstract static methods, then this works, and turns out to be the easiest solution for me to adapt to:

class TestBase<ChildType> where ChildType : TestBase<ChildType> {
    //public static abstract void TargetMethod();

    public static void Operation() {
        typeof(ChildType).GetMethod("TargetMethod").Invoke(null, null);
    }
}

class TestChild : TestBase<TestChild> {
    public static void TargetMethod() {
        Console.WriteLine("Child class");
    }
}

But I am still marking Stafan as the solution because using instance inheritance is probably the best recommendation for anyone in a similar situation. But I simply would have to rewrite too much code for it.

Solution 4

Ok here is what I have done

public abstract class Base<T>
    where T : Base<T>, new()
{
    #region Singleton Instance
    //This is to mimic static implementation of non instance specific methods
    private static object lockobj = new Object();
    private static T _Instance;
    public static T Instance
    {
        get
        {
            if (_Instance == null)
            {
                lock (lockobj)
                {
                    if (_Instance == null)
                    {
                        _Instance = new T();
                    }

                }
            }
            return _Instance;
        }
    }

    #endregion //Singleton Instance

    #region Abstract Definitions

    public abstract T GetByID(long id);
    public abstract T Fill(SqlDataReader sr);

    #endregion //Abstract Definitions
}

public class InstanceClass : Base<InstanceClass>
{
    //empty constructor to ensure you just get the method definitions without any
    //additional code executing
    public InstanceClass() { }


    #region Base Methods

    public override InstanceClass GetByID(long id)
    {
        SqlDataReader sr = DA.GetData("select * from table");
        return InstanceClass.Instance.Fill(sr);
    }

    internal override InstanceClass Fill(SqlDataReader sr)
    {
         InstanceClass returnVal = new InstanceClass();
         returnVal.property = sr["column1"];
         return returnVal;
    }
}

I think this will be a viable solution for what you want to do without breaking too many purist OO principles.

Share:
14,664
Nick Whaley
Author by

Nick Whaley

Updated on June 25, 2022

Comments

  • Nick Whaley
    Nick Whaley about 2 years

    Static inheritance works just like instance inheritance. Except you are not allowed to make static methods virtual or abstract.

    class Program {
        static void Main(string[] args) {
            TestBase.TargetMethod();
            TestChild.TargetMethod();
            TestBase.Operation();
            TestChild.Operation();
        }
    }
    
    class TestBase {
        public static void TargetMethod() {
            Console.WriteLine("Base class");
        }
    
        public static void Operation() {
            TargetMethod();
        }
    }
    
    class TestChild : TestBase {
        public static new void TargetMethod() {
            Console.WriteLine("Child class");
        }
    }
    

    This will output:

    Base class
    Child class
    Base class
    Base class
    

    But I want:

    Base class
    Child class
    Base class
    Child class
    

    If it I could on static methods, I would make TargetMethod virtual and it would do the job. But is there a work around to get the same effect?

    Edit: Yes, I could put a copy of Operation in the child class, but this would require copy and pasting a large bit of code into every child, which in my case is about 35 classes, a maintenance nightmare.