如何与派生类正确共享基类静态属性



我有一个基类,其中包含执行http请求的基本逻辑。但是我需要某种开关,因为根据用户设置的配置,url 的域会发生变化。

在此基础上,我创建了一个静态属性,该属性包含一个枚举,负责为我提供所需的基值。最重要的是,基类将通过 nuget 包分发,因此它对用户来说在某种程度上是密封的,用户只需要实现其必填字段,就可以使用在其父级上定义的任何逻辑。

所以基本上到目前为止我想出了这个解决方案。

public abstract class Base{
protected static Environment Environment { get; set; }
public static Init(Environment NewEnvironment){
Environment = NewEnvironment;
}
public void UseEnvironment(){
//use the selected environment on the method
}
}
public A : Base{ 
public void UseAEnvironment(){
UseEnvironment(); //using the environment defined with A.init() call
}
}
public B : Base{ 
public void UseBEnvironment(){
UseEnvironment(); //using the environment defined with B.init() call
}

我知道内存中只有一个静态属性的副本,因此当您将其设置为 A 类的值时,B 最终将使用相同的值。

我需要能够做

A.Init(Environment.Debug);
B.Init(Environment.Release);

因此,当我运行程序时,类 A 中定义的所有方法都将使用 Debug 值运行,而类 B 将具有 Release 值。

我的解决方案没有做我需要的,有没有办法让它工作,或者是否有更好的架构决策来避免这种情况并实现类似的结果?

如果您有:

public abstract class Base<T> where T : Base<T>
{
protected static Environment Environment { get; private set; }
public static void Init(Environment newEnvironment)
{
Environment = newEnvironment;
}
}

然后:

public class A : Base<A>
{
...
}
public class B : Base<B>
{
...
}

然后你可以做:

Base<A>.Init(Environment.Debug);
Base<B>.Init(Environment.Release);

它之所以有效,是因为在Base<T>中,每次替换T的东西都有自己的静态成员。也就是说,每个构造的泛型类型("封闭"泛型类型(都有单独的静态字段。

您也可以将其写为:

A.Init(Environment.Debug);
B.Init(Environment.Debug);

但我认为这有点令人困惑,即使它是一个更紧凑的语法。

这似乎是一个有点奇怪的设计。也许像编译器指令(#if DEBUG(或通过App.config或类似的东西会更适合?

无论如何,如果不是..类似以下内容应该可以工作

public abstract class Base<T> where T : Base<T>
{
private static readonly IDictionary<Type, Environment> _Environments = new Dictionary<Type, Environment>();
public static void Init(Environment NewEnvironment)
{
_Environments[typeof(T)] = NewEnvironment;
}
protected Environment GetEnvironment()
{
if (!_Environments.ContainsKey(typeof(T)))
return default(Environment);
return _Environments[typeof(T)];
}
}
public class A : Base<A> {
// ...
}
public class B : Base<B> {
// ...
}

我不喜欢以下建议的代码,但它代表了最小的代码剧变量,以提供我认为您要做的事情。 请注意抽象基类中删除的静态声明。

public abstract class Base {
protected Environment Environment { get; set; }
public Init(Environment NewEnvironment) {
Environment = NewEnvironment;
}
}
public A : Base{ 
public void UseEnvironment() {
}
}
public B : Base{ 
public void UseEnvironment() {
}
}

然后初始化。

static A DebugHttpAccess;
static B RealeaseHttpAccess;
DebugHttpAccess = new A();
DebugHttpAccess.Init(Environment.Debug);
RealeaseHttpAccess= new B();
RealeaseHttpAccess.Init(Environment.Release);

最后按照其他更高级别的逻辑使用:

if ( needDebugHttpTracing )
DebugHttpAccess.UseEnvironment();
else
ReleaseHttpAccess.UseEnvironment();

我怀疑满足您要求的正确解决方案涉及控制反转和一个可以将 Http 访问的生命周期作为单例类进行管理的容器。容器将注入由其他进程范围的配置设置定义的相应 Http 访问实例。

有关 IOC 容器的示例,请参阅 autofac.org。

最新更新