每当我读到RE这个问题或静态继承的类似主题时,回复通常都是不支持的(我们知道),原因是因为这是一个糟糕的设计并且可能存在更好的方法。我很想找到一个更好的方法,所以我愿意接受所有的建议 - 这就是我想要做的。
我有一个没有实例数据的类。所有方法都是静态的。我们称之为class BaseStatic
。我现在想要一个新的静态类(当然好几个但是坚持一个)继承自这个静态类并添加一些新的静态方法,让我们调用这个SubStatic
。
我希望消费者能够写下:
SubStatic.MethodFromSub();
以及
SubStatic.MethodFromBase();
我知道我也可以写:
BaseStatic.MethodFromBase()
显式,但消费者必须知道哪个类实现了哪些方法。我不能用继承来做这个,因为我不能从另一个继承一个静态类。那么有什么更好的方法呢?
现在,我知道我可以将这些类作为实例类,并且我可以将所有方法定义为静态 - 这将给我上面描述的行为,但会导致其他问题,即:
执行此操作时:SubStatic.MethodFromBase()
未调用SubStatic
静态构造函数,因为该方法在父静态类中运行(调用父级的静态构造函数)
如果其中一个静态父方法需要调用子类可以覆盖的另一个方法,我需要在子类中使用虚拟静态方法。我知道我不能拥有。
显然糟糕的设计 - 任何人都可以帮我重做吗?我知道我可以使用实例继承并正确使用虚方法(我已经让它以这种方式工作)但客户端代码总是必须创建一个实例(或者我想一些单例)。
答案 0 :(得分:4)
这可以达到您的目的,但我当然会包含一些异常处理,并伴随其实施,提供大量文档,说明原因和工作原理。
运行Base
的静态构造函数(一次)时,将对应用程序域中当前加载的所有程序集进行编目,选择从Base
派生的类型。迭代这些,我们运行静态构造函数。值得注意的是,这不再保证每个实现的cctor将只运行一次,必须将逻辑添加到每个实现中以重新生成该断言。此外,运行Base
的cctor之后加载的类型不会通过调用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。
答案 1 :(得分:2)
您可以使用Generics实现此目的。例如,你可以使用类似的东西:
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();
}
}