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

问题描述 投票:0回答:4

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

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

c# class inheritance static
4个回答
3
投票

如果您有:

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);

它之所以有效,是因为

T
Base<T>
的每次替换都有其自己的静态成员。也就是说,每个构造泛型类型(“封闭”泛型类型)都有单独的静态字段。

你也可以写成:

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

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


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> {
    // ...
}

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。


0
投票

就我而言,我也首先采用了泛型类技巧,但相对于继承而言,更喜欢组合有助于我保持代码更加灵活和可读。所以下面的程序,其中

Environment
变量是共享的:

public enum Environment { Debug, Release }

public abstract class Base {
    protected static Environment Environment { get; set; }
    protected static void Init(Environment NewEnvironment) { Environment = NewEnvironment; }
}

public class A : Base { 
    public static void Init() { Init(Environment.Debug); }
    public static void PrintEnvironment() { Console.WriteLine(Environment); }
}

public class B : Base { 
    public static void Init() { Init(Environment.Release); }
    public static void PrintEnvironment() { Console.WriteLine(Environment); }
}

void Main() {
    A.Init();
    B.Init();
    A.PrintEnvironment(); // Prints: Release
    B.PrintEnvironment(); // Prints: Release
}

首次替换为:

public enum Environment { Debug, Release }

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

public class A : Base<A> { 
    public static void Init() { Init(Environment.Debug); }
    public static void PrintEnvironment() { Console.WriteLine(Environment); }
}

public class B : Base<B> { 
    public static void Init() { Init(Environment.Release); }
    public static void PrintEnvironment() { Console.WriteLine(Environment); }
}

void Main() {
    A.Init();
    B.Init();
    A.PrintEnvironment(); // Prints: Debug
    B.PrintEnvironment(); // Prints: Release
}

最终是:

public enum Environment { Debug, Release }

public sealed class Base {
    public Environment Environment { get; set; }
    public void Init(Environment NewEnvironment) { Environment = NewEnvironment; }
}

public class A { 
    public static Base MyBase = new Base();
    public static void Init() { MyBase.Init(Environment.Debug); }
    public static void PrintEnvironment() { Console.WriteLine(MyBase.Environment); }
}

public class B { 
    public static Base MyBase = new Base();
    public static void Init() { MyBase.Init(Environment.Release); }
    public static void PrintEnvironment() { Console.WriteLine(MyBase.Environment); }
}

void Main() {
    A.Init();
    B.Init();
    A.PrintEnvironment(); // Prints: Debug
    B.PrintEnvironment(); // Prints: Release
}
© www.soinside.com 2019 - 2024. All rights reserved.