简体   繁体   English

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

[英]How to properly share base class static property with derived classes

I have a base class that contains the basic logic to perform an http request. 我有一个基类,其中包含执行http请求的基本逻辑。 However I need to have some kind of switch because dependending on the configuration set by the user, the domain of the url will change. 但是,我需要进行某种切换,因为取决于用户设置的配置,URL的域将发生变化。

Based on that I created a static property that holds an enum responsible to give me the base value I need. 基于此,我创建了一个静态属性,其中包含一个枚举,负责为我提供所需的基本值。 On top of that, the base class will be distribuited via nuget package, so it is somewhat sealed to the users, that need only to implement its required fields and can use any logic defined on its parent. 最重要的是,该基类将通过nuget包进行分发,因此它对用户有些密封,只需要实现其必填字段并可以使用在其父级上定义的任何逻辑即可。

So basically I came up with this solution so far. 所以到目前为止,基本上我想出了这个解决方案。

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
    }

I know that there is only one copy of the static property in memory, thus when you set it to a value for the A class, B will end up using the same value. 我知道内存中只有一个静态属性副本,因此当您将其设置为A类的值时,B最终将使用相同的值。

I need to be able to do 我需要能够做

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

So when I run the program, all methods defined in class A will run with the Debug value, while class B will have the Release value. 因此,当我运行程序时,在类A中定义的所有方法都将使用Debug值运行,而类B将具有Release值。

My solution does not do what I need, is there a way to make it work, or is there any better architecture decisions to avoid this situation and accomplish a similar result? 我的解决方案无法满足我的需要,是否有办法使其正常工作,或者是否有更好的体系结构决策来避免这种情况并取得相似的结果?

If you have: 如果你有:

public abstract class Base<T> where T : Base<T>
{
  protected static Environment Environment { get; private set; }

  public static void Init(Environment newEnvironment)
  {
    Environment = newEnvironment;
  }
}

And then: 接着:

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

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

then you can just do: 那么您可以执行以下操作:

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

It works because each substitution of something for T in Base<T> has its own static members. 之所以起作用,是因为在Base<T>每次用T替换某个东西都有其自己的静态成员。 That is, each constructed generic type ("closed" generic type) has separate static fields. 也就是说,每个构造的泛型类型(“封闭”泛型类型)都有单独的静态字段。

You could also write it as: 您也可以将其编写为:

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

but I would consider that slightly confusing, even if it is a more compact syntax. 但即使语法比较紧凑,我也会觉得有些困惑。

It seems like a bit of an odd design. 似乎有点奇怪的设计。 Maybe something like compiler directives (#if DEBUG) or configuration via App.config or similar would be better suited? 也许像编译器指令(#if DEBUG)或通过App.config或类似的配置更合适?

Anyway, if not .. something like the following should work 无论如何,如果没有..类似下面的东西应该工作

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

I do not like the following proposed code but it represents the smallest amount of code upheaval to provide what I think you are trying to do. 我不喜欢下面建议的代码,但是它代表了我想尝试做的事情中最小的代码动荡。 Note to dropped static declarations in the abstract base class. 请注意在抽象基类中删除的静态声明。

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() {
     }
}

Then initialise. 然后初始化。

static A DebugHttpAccess;
static B RealeaseHttpAccess;

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

Finally use as dictated by other higher level logic: 最终使用其他高层逻辑所规定的:

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

I suspect the proper solution to your requirement involves inversion of control and a container that can manage the life time of your Http access as a singleton class. 我怀疑对您的要求的正确解决方案包括控制反转和可以作为单例类来管理Http访问的生存时间的容器。 The container would inject the appropriate Http access instance as defined by other process-wide configuration settings. 容器将注入其他进程范围的配置设置所定义的适当的Http访问实例。

See autofac.org for an example of an IOC container. 有关IOC容器的示例,请参见autofac.org。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM