2016-12-06 49 views
0

我剛想出了一個非常奇怪的問題,我無法弄清楚如何解決它。C#繼承 - 保存對最後一個實例的引用

我有3類,類A是B和C的基礎上,即:

class A { ... } 
class B : A { ... } 
class C : B { ... } 

現在我想有在這些類,其存儲每個類別的最後一個對象的靜態屬性創建,例如:

class A 
{ 
    static public A lastInstance; 
} 

class B : A 
{ 
    public B() 
    { 
     lastInstance = this; 
    } 
} 

class C : A 
{ 
    public C() 
    { 
     lastInstance = this; 
    } 
} 

我想實現的是能夠獲得實例爲每個子類,例如:

var v1 = new B(); 
var v2 = new C(); 

var v3 = B.lastInstance; // v3 == v1 and v3 != v2 
var v4 = C.lastInstance; // v4 == v2 and v4 != v3 

是否有可能?

對我來說看起來很有希望的唯一方法是在C# Static instance members for each inherited class中顯示:是否真的有必要避免爲每個類手動定義一個靜態成員?

回答

3

我認爲這可能與Dictionary來完成,這就是我能想到的,現在唯一的辦法:

class A { 
    static Dictionary<Type, A> _LastInstances = new Dictionary<Type, A>(); // because every subclass will inherit from A 
    public static A LastInstance { 
     get { 
      if (_LastInstances.ContainsKey(GetType())) { 
       return _LastInstances[GetType()]; 
      } 
      return null; 
     } 

     protected set { 
      if (_LastInstances.ContainsKey(GetType())) { 
       _LastInstances[GetType()] = value; 
      } else { 
       _LastInstances.Add(GetType(), value); 
      } 
     } 
} 

class B : A { 
    public B(){ 
     LastInstance = this; 
    } 
} 
+0

我選擇你的解決方案作爲答案,因爲它似乎是更一般和可擴展!非常感謝您的分享! – Brutus

1

因爲靜態成員不繼承,您將無法訪問B.lastInstance如果A類定義了lastInstance。您鏈接的建議似乎是合理的。雖然我沒有足夠的信息說明你爲什麼試圖這樣做,但你可以考慮使用一個工廠類來保存最新創建的對象。

下面是一個例子。如果您打算從A派生出許多類,這不是一個好的長期解決方案。

class HoldLastKnownFactory 
{ 
    B CreateB() { ... } 
    C CreateC() { ... } 
    B LastB { get {...} } 
    C LastC { get {...} } 
} 
2

起初:是的,您可以。但是你在執行時錯過了兩點。

  1. 正如你宣佈lastInstance在A類中公開的那樣,每個派生類都可以使用它。當你聲明爲靜態時,A的每個實例都會將其自身複製到它中。但是,B,C和其他每個ID都來自A的類的實例也將如此:它們全都使用相同的實例。因此最後一個instatiated類被保存,並且之前被實例化的所有東西都被覆蓋。

爲了克服這一點,你必須對每類,您可以通過使用new修改的派生類實現的靜態屬性LastInstance(我切換到我的命名約定)

public class A 
{ 
    public static A LastInstance { get; private set; } 
    ... 
} 

public class B : A 
{ 
    public static new B LastInstance { get; private set; } 
    ... 
} 

但是你並沒有完成這項工作,因爲

  1. 當你創建一個B的新實例時,(默認)construstor首先打一個呼叫進入A的構造器。 hus對任何已經創建的基類實例的引用被當前創建的派生類實例覆蓋。所以,你的構造應該是這樣的:
public class A 
{ 
    public static A LastInstance { get; private set; } 
    public A() 
    { 
     if (this.GetType() == typeof(A)) 
     { 
     LastInstance = this; 
     } 
    } 
} 

public class B : A 
{ 
    public static new B LastInstance { get; private set; } 
    public B() 
    { 
     if (this.GetType() == typeof(B)) 
     { 
     LastInstance = this; 
     } 
    } 
} 

這樣,您將得到正確的最後創建的實例(如果有的話)在每個類的靜態LastInstance

希望這可以幫助

+0

你的第二個陳述是錯誤的,因爲即使它從派生類調用構造函數,它仍然使用'GetType()'中的實例類類型。幾天前,SO中甚至有一個很好的例子。第二個例子唯一的問題是,當你從ctor中刪除'if'語句時,每個'LastInstance'都會有相同的實例。 –

+0

如果我認識你,你錯了。聲明(2.)是正確的(並經過測試)。如果你有'var b = new B();'調用鏈是 1.輸入ctor B, 2.執行ctor A的主體(用'B' as this.GetType) 3.執行ctor B. 是的,「if」語句的目的是過濾不需要的(派生的)實例。但我想,這很明顯。 –

+0

我的意思是'GetType()'將總是返回實例化的類型,所以對於'B.GetType()'它將在每個構造函數B => A'中是相同的類型。我不是因爲它工作正常才能工作。也許我的評論不清楚,或者我誤解了第二個例子的描述。 –

相關問題