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

时间:2009-04-18 12:16:37

标签: c# 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个类,这是一个维护噩梦。

4 个答案:

答案 0 :(得分:12)

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

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

答案 1 :(得分:8)

您可以将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更改它。你可能会或可能不会关心这一点。如果你这样做,泛型或Dictionary<Type, Action>可能有所帮助。

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

答案 2 :(得分:2)

如果您正在寻找抽象静态方法,那么这是有效的,并且结果是我最容易适应的解决方案:

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

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

答案 3 :(得分:2)

好的,这就是我所做的

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

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