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

时间:2017-08-05 20:45:37

标签: c# class inheritance static

我有一个基类,它包含执行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值。

我的解决方案不能满足我的需求,有没有办法让它工作,或者是否有更好的架构决策来避免这种情况并取得类似的结果?

3 个答案:

答案 0 :(得分:2)

如果你有:

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

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

然后:

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

那么你可以这样做:

T

这很有效,因为Base<T>A.Init(Environment.Debug); B.Init(Environment.Debug); 的某些内容替换都有自己的静态成员。也就是说,每个构造的泛型类型(“封闭”泛型类型)都有单独的静态字段。

你也可以把它写成:

spark.executorEnv.PYTHON_EGG_CACHE="./.python-eggs/"
spark.executorEnv.PYTHON_EGG_DIR="./.python-eggs/"
spark.driverEnv.PYTHON_EGG_CACHE="./.python-eggs/"
spark.driverEnv.PYTHON_EGG_DIR="./.python-eggs/"

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

答案 1 :(得分:1)

这似乎有点奇怪的设计。也许类似于编译器指令(#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> {
    // ...
}

答案 2 :(得分:0)

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

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。