8

每当我阅读 RE 这个问题或类似的静态继承主题时,回复通常是不支持这(我们知道),原因是因为这是一个糟糕的设计,可能有更好的方法来做。我很想找到一种更好的方法,所以我愿意接受所有建议——这就是我想要做的。

我有一个没有实例数据的类。所有方法都是静态的。让我们称之为class BaseStatic. 我现在想要一个新的静态类(当然有几个,但让我们坚持一个),它继承自这个静态类并添加一些新的静态方法,我们称之为SubStatic.

我希望消费者能够写的是:

SubStatic.MethodFromSub();

并且

SubStatic.MethodFromBase();

我知道我也可以写:

BaseStatic.MethodFromBase()

显式地但随后消费者必须知道哪个类实现了哪些方法。我不能通过继承来做到这一点,因为我不能从另一个静态类继承一个静态类。那么有什么更好的方法呢?

现在,我知道我可以将这些类作为实例类,并且我可以将所有方法定义为静态 - 这会给我上面描述的行为,但会导致其他问题,即:

  1. 当我这样做时:不调用静态构造函数SubStatic.MethodFromBase()SubStatic因为该方法在父静态类中运行(调用父静态构造函数)

  2. 如果其中一个静态父方法需要调用另一个子类可以覆盖的方法,我需要子类中的虚拟静态方法。我知道我不能拥有。

显然设计如此糟糕 - 任何人都可以帮我重做它吗?我知道我可以使用实例继承并正确使用虚拟方法(我已经以这种方式工作)但是客户端代码总是必须创建一个实例(或者我想是一些单例)。

4

2 回答 2

4

这可以满足您的目的,尽管我当然会包括一些异常处理,并在其实现中附带大量关于其工作原理和方式的文档。

Base运行(一次)的静态构造函数时,当前加载到应用程序域中的所有程序集都会被编目,选择从Base. 遍历这些,我们运行静态构造函数。值得注意的是,这不再保证每个实现的 cctor 将只运行一次,必须将逻辑添加到每个实现中以重新做出该断言。此外,在 cctor forBase运行后加载的类型不会通过调用Base

要模拟虚方法,请使用new关键字隐藏基方法。您可以通过使用声明类的名称对其进行限定来调用基方法(如B示例中的类)

using System;
using System.Linq;
using System.Runtime.CompilerServices;

namespace ConsoleApplication6
{
    public class Base
    {
        static Base()
        {
            Console.WriteLine("Base cctor");

            var thisType = typeof (Base);
            var loadedTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes());
            var derivations = loadedTypes.Where(thisType.IsAssignableFrom);

            foreach(var derivation in derivations)
            {
                RuntimeHelpers.RunClassConstructor(derivation.TypeHandle);
            }
        }

        public static void Foo()
        {
            Console.WriteLine("Bar");
        }
    }

    public class A : Base
    {
        static A()
        {
            Console.WriteLine("A cctor");
        }
    }

    public class B : Base
    {
        static B()
        {
            Console.WriteLine("B cctor");
        }

        public new static void Foo()
        {
            Console.WriteLine("Bar!!");
            Base.Foo();
        }
    }

    class Program
    {
        static void Main()
        {
            Console.WriteLine("A:");
            A.Foo();
            Console.WriteLine();
            Console.WriteLine("B:");
            B.Foo();
            Console.WriteLine();
            Console.WriteLine("Base:");
            Base.Foo();
            Console.ReadLine();
        }
    }
}

编辑

另一种选择在于 CRTP(或 C# 范例中的 CRGP)或奇怪的重复模板(通用)参数模式

using System;
using System.Runtime.CompilerServices;

namespace ConsoleApplication6
{
    public class Base<T>
        where T : Base<T>
    {
        static Base()
        {
            RuntimeHelpers.RunClassConstructor(typeof (T).TypeHandle);
        }

        public static void Foo()
        {
            Console.WriteLine("Bar");
        }
    }

    public class Base : Base<Base>
    {
    }

    public class A : Base<A>
    {
        static A()
        {
            Console.WriteLine("A cctor");
        }
    }

    public class B : Base<B>
    {
        static B()
        {
            Console.WriteLine("B cctor");
        }

        public new static void Foo()
        {
            Console.WriteLine("Bar!!");
            Base<B>.Foo();
        }
    }

    class Program
    {
        static void Main()
        {
            Console.WriteLine("A:");
            A.Foo();
            Console.WriteLine();
            Console.WriteLine("B:");
            B.Foo();
            Console.WriteLine();
            Console.WriteLine("Base:");
            Base.Foo();
            Console.ReadLine();
        }
    }
}

在这种情况下,当我们调用一个静态方法时,A我们实际上调用的Base<A>是不同的方法Base<B>Base因此我们实际上可以确定该方法是如何被调用的并运行适当的 cctor。

于 2012-10-22T05:43:49.850 回答
2

您可以通过使用泛型来实现这一点。例如,您可以使用类似的东西:

public class MainStatic<T> where T : MainStatic<T>
{
    public static void Foo()
    {
    }

    static MainStatic()
    {
        RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle);
    }
}

public class SubStatic : MainStatic<SubStatic>
{
    public static void Bar()
    {
    }
}

public class Instance
{
    public void FooBar()
    {
        SubStatic.Foo();
        SubStatic.Bar();
    }
}
于 2012-10-22T07:22:26.110 回答