C#虚拟(或抽象)静态方法

静态inheritance就像实例inheritance一样工作。 除非您不允许将静态方法设为虚拟或抽象。

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"); } } 

这将输出:

 Base class Child class Base class Base class 

但我想要:

 Base class Child class Base class Child class 

如果我可以在静态方法上,我会使TargetMethod虚拟,它将完成这项工作。 但有没有可以达到同样的效果呢?

编辑:是的,我可以在子类中放置一个Operation副本,但这需要复制并将大量代码粘贴到每个子节点,在我的情况下大约是35个类,这是一个维护噩梦。

不,你不能覆盖静态方法。 “static”也意味着它是由编译器静态绑定的,因此在运行时找不到要调用的实际方法,但在编译时绑定。

你应该做的是使类非静态。 使方法成为虚拟并覆盖它并充分利用实际inheritance。 然后,如果您确实需要它,请为您的类的引用创建一个静态入口点。 例如一个静态工厂,单例(在大多数情况下它是一个反模式但是和静态类一样好)或者只是一个静态属性。

您可以将TargetMethod存储为委托,子类可以根据需要进行更改:

 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"); }); } } 

因为这些是静态实例,所以_targetMethod在所有实例之间共享 – 在TestChild更改它也会为TestBase更改它。 你可能会或可能不会关心这一点。 如果你这样做,generics或Dictionary可能会有所帮助。

但总的来说,如果你不坚持静态,或者使用组合而不是inheritance,你会有更轻松的时间。

如果你想做抽象静态方法,那么这是有效的,并且结果是我最容易适应的解决方案:

 class TestBase where ChildType : TestBase { //public static abstract void TargetMethod(); public static void Operation() { typeof(ChildType).GetMethod("TargetMethod").Invoke(null, null); } } class TestChild : TestBase { public static void TargetMethod() { Console.WriteLine("Child class"); } } 

但我仍然将Stafan标记为解决方案,因为使用实例inheritance可能是类似情况下任何人的最佳建议。 但我只需要为它重写太多代码。

好的,这就是我所做的

 public abstract class Base where T : Base, 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 { //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; } } 

我认为,如果不打破太多纯粹的OO原则,这将是您想要做的可行解决方案。