【发布时间】:2016-07-04 01:11:06
【问题描述】:
我遇到了类设计难题:我有一个通用基类和多个派生类。基础是一个提供通用功能的CRTP 类,其中一些需要继承类特定的数据。因此,基类是抽象的,子类必须实现某些“提供者”方法。例如:
public abstract class Base<T> where T : Base<T>, new() {
private static T reference = new T();
public static int Foo => reference.GetFoo();
public static string Bar => reference.GetBar();
protected abstract int GetFoo();
protected abstract string GetBar();
// ...
}
问题是信息不是特定于实例的,应该可以从通用参数访问。所以使用上面的例子,这个方法可以在另一个类中:
public void ComputeSomething<T>() where T : Base<T>, new() {
int foo = Base<T>.Foo;
// ...
}
或者如果子类已知:ChildClass.Foo
这可行,但总体而言,该解决方案感觉“肮脏”,因为我讨厌用类型信息来混乱每个实例,并且基类必须保留一个 reference 实例(如何在其基类中创建子类仍然有点弯曲我的大脑,通常看起来是个坏主意)。我会将信息放在缓存或工厂或其他东西中,但我无法控制所有子类,因此系统必须是可扩展的。我研究了使用属性,但是(据我所知)没有办法强制在编译时存在某些属性。真的,我觉得我需要静态接口或静态抽象成员,但 C# 没有这些。
所以我的问题是:这种问题一般是怎么解决的?
【问题讨论】:
-
您是否能够更改/重构使用静态成员的代码以仅使用抽象成员?通常,在可测试性/控制反转/依赖注入盛行的世界中,您会寻求让所有代码都利用非静态成员,以便它们很容易被替换或模拟......
-
关于您的陈述“如何在其基类中创建子类仍然让我有点不知所措,而且通常看起来是个坏主意” - 是的!你是对的,坏主意。在构建依赖等方面,您会严重限制自己。
-
是的,我当然可以重构代码,反正它更像是一个原型。在很多地方(如示例中),这会导致类似
new T().Foo的内容,这似乎不太正确。我开始认为我需要一个单独的提供程序类或其他东西
标签: c# generics class-design crtp