2017-08-05 82 views
0

我有一個基類,它包含執行一個http請求的基本邏輯。不過,由於依賴於用戶設置的配置,我需要進行某種切換,因此網址的域名將會更改。如何正確地與派生類共享基類靜態屬性

基於此,我創建了一個靜態屬性,其中包含一個枚舉,負責給我所需的基值。最重要的是,基類將通過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類中定義的所有方法都與調試運行值,而B類將有釋放值。

我的解決方案沒有做到我需要的東西,有沒有辦法讓它工作,或者是否有更好的架構決策來避免這種情況並實現類似的結果?

+2

如果它是'static',它不屬於一個實例。看起來你的'環境'應該屬於一個實例。爲什麼它是靜態的呢? – Andrew

+0

是不是使用靜態屬性的東西,應該避免?也許你正在試圖解決[XY問題](http://xyproblem.info/)? –

回答

2

如果您有:

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

但我認爲稍顯混亂,即使它是一個更簡潔的語法。

+0

獲得我的投票,這是比我的答案更復雜的解決方案。我仍然認爲一個適當的長期解決方案將利用IOC容器,但我很欣賞提供的答案是圍繞問題中的示例代碼形成的。 – camelCase

+0

好的,但也許我應該放棄提問者希望有'靜態'字段而不是固定他的代碼。類似於'公共抽象類基礎{0}公共抽象環境環境{獲取;保護組; }}'成員是非靜態的_could_會更好。至少比較平常。但我不確切知道這是用來做什麼的。 –

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

爲什麼字典<,>沒有用,它永遠不會有多個鍵,即'typeof(T)'。 'static'字段'_Environments'在不同構造的泛型類型之間不被共享。 (查看我的答案) –

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。