2015-06-06 52 views
5

我有一個從Agent繼承的子類Bicycle。代理商有一個屬性取決於自行車來定義它。即,代理的物理模型需要用基於每個自行車定義的速度和加速度約束來初始化,並且對於另一種類型的代理將是不同的。強制子類在計算後初始化父屬性

我遇到的問題是,我無法通過我需要計算的參數(速度/加速度需要計算從理論分佈中繪製它們),因爲當然,子類還沒有構造器在base()構造函數中被實例化。

每個單車實例計算一次,但多次使用,所以一個簡單的靜態方法將無法完成這項工作。在計算完父母后,我可以在父母中調用protected方法,但AFAIK無法在孩子中執行此操作,尤其是在未來的孩子中,我可能不會寫這些方法。

因此,例如,我可以:

public abstract class Agent 
{ 
    protected IPhysics PluginPhysics { get; set; } 

    protected Agent(...) 
    { 
    } 
} 

public class Bicycle : Agent 
{ 
    private double maxA; 

    public Bicycle(Object anotherParameter) : base(...) 
    { 
     maxA = ComputationOfMaxA(); 
     this.PluginPhysics = new Physics(anotherParameter, maxA); 
    } 

    private static double ComputationOfMaxA() 
    { 
     ... 
    } 
    ... 
} 

我也可以:

public abstract class Agent 
{ 
    protected IPhysics PluginPhysics { get; private set; } 

    protected Agent(...) 
    { 
    } 

    protected void SetupPhysics(Physics physics) 
    { 
     this.PluginPhysics = physics; 
    } 
} 

public class Bicycle : Agent 
{ 
    private double maxA; 

    public Bicycle(Object anotherParameter) : base(...) 
    { 
     maxA = ComputationOfMaxA(); 
     SetupPhysics(new Physics(anotherParameter,maxA)); 
    } 

    private static double ComputationOfMaxA() 
    { 
     ... 
    } 

    ... 
} 

我寧願不做這類原因,因爲沒有編譯時的方式,以確保兒童初始化我可以想到的PluginPhysics,並且我寧願PluginPhysics一旦它被初始化就不能被改變。我也寧願沒有需要在Bicycle類之外的部分Physics。我明白所有這些事情可能不是同時可能的。

因此,在調用任何相關類對象之前,在父類中缺少措辭強烈的文檔或一堆運行時空的檢查,是否存在明顯的C#方式 - 我缺少強制一個孩子在使用前初始化一個父類字段,如果你不能在構造函數中做?

+2

我調整了一下代碼,使其更加明顯,您在創建物理對象之前依靠ComputationOfMaxA完成。 –

回答

3

d4Rk's answer是非常接近的,但是你應該儘量不要從構造函數中調用虛方法爲bad things can happen。但是,如果您使用延遲加載技巧和ISupportInitialize的組合,則可以在構造函數完成之後推遲創建插件。

public abstract class Agent : ISupportInitialize 
{ 
    private bool _initialized = false; 

    private IPhysics _pluginPhysics; 
    protected IPhysics PluginPhysics 
    { 
     get 
     { 
      if(!_initialized) 
       EndInit(); 
      return _pluginPhysics; 
     } 
    } 

    protected Agent(...) 
    { 
    } 

    protected abstract IPhysics CreatePhysics(); 

    ISupportInitialize.BeginInit() 
    { 
     //We make this a explicit implementation because it will not 
     //do anything so we don't need to expose it. 
    } 

    public void EndInit() 
    { 
     if(_initialized) 
      return; 

     _initialized = true; 
     _pluginPhysics = CreatePhysics(); 
    } 
} 

public class Bicycle : Agent 
{ 
    private double maxA; 
    Object _anotherParameter; 

    public Bicycle(Object anotherParameter) 
    { 
     _anotherParameter = anotherParameter; 
    } 
    protected override IPhysics CreatePhysics() 
    { 
     ComputationOfMaxA(); 
     return new Physics(anotherParameter, maxA); 
    } 
} 

類的用戶需要調用EndInit()後,他們得到一個對象回導致要創建的IPhysics對象,但是如果他們忘記調用初始化函數的物理對象上,吸氣將觸發在第一次使用時初始化調用本身。

如果沒有ISupportInitialize接口,並且在基類上只有一個公開的Initalize()方法,我可以做所有的事情,但我喜歡在適合時公開框架接口。

+0

這比我在考慮的那種空檢查更加優雅,因爲它使用了一個明確的用於初始化「共依賴屬性」的適當接口,這基本上就是我在這裏所瞭解的。它當然感覺最「C#ish」。謝謝。 – Smalltown2k

2

如何強制子類實現CreatePhysics方法,並在基礎ctor中調用它?

像這樣:

public abstract class Agent 
{ 
    protected IPhysics PluginPhysics { get; private set; } 

    protected Agent(...) 
    { 
     var physics = CreatePhysics(); 
     SetupPhysics(physics); 
    } 

    void SetupPhysics(IPhysics physics) 
    { 
     this.PluginPhysics = physics; 
    } 

    protected abstract IPhysics CreatePhysics(); 
} 

public class Bicycle : Agent 
{ 
    private double maxA; 

    protected override IPhysics CreatePhysics() 
    { 
     ComputationOfMaxA(); 
     return new Physics(maxA); 
    } 
} 
+0

只要物理插件不需要通過自行車構造函數進入的東西,這很不錯,不幸的是我的情況。我可能會更新這個問題。 – Smalltown2k

+0

一般來說,在構造函數中調用一個抽象/虛擬類是不被贊同的。這是因爲子構造函數不會開始運行,並且類級別的變量不會被實例化,當您有多個繼承級別時,這會變得非常棘手。 –

+0

但是,如果將此方法與['ISupportInitialize'](https://msdn.microsoft.com/en-us/library/system.componentmodel.isupportinitialize%28v=vs.110%29.aspx)結合使用,那麼您有'EndInit()'調用'CreatePhysics()'一切都會好的。 –

2

如何使構造函數Agent採取IPhysics對象,並在你的Bicycle類使其protected然後,你不得不調用哪個設置你的類的基礎上構造屬性:

public class Agent 
{ 
    protected IPhysics PluginPhysics { get; private set; } 

    protected Agent(IPhysics physicsPlugin) 
    { 
     PluginPhysics = physicsPlugin; 
    } 
} 

public class Bicycle : Agent 
{ 
    public Bicycle(IPhysics physicsPlugin) 
     : base(physicsPlugin) 
    { 
     Console.WriteLine("Bicycle ctor"); 
    } 
} 
+0

你在哪裏執行'physicsPlugin'的計算? – d4Rk

+0

我可能最終會遇到這個問題。我試圖避免的是某些事物需要從Bicycle類外部進入該物理插件構造器。雖然我很欣賞這不是我現在更新的問題。 – Smalltown2k

+0

如果你不想要自行車課外的那些零件,那麼爲什麼不把所有內容都放在'Agent'中?我想我對你在這裏想達到的目標有點困惑。 – DavidG