2013-07-29 122 views
2

我很難搞清楚如何構造這個。覆蓋臨時對象的屬性?

我有一個類VehicleState與特性,包括passengers

public class VehicleState 
{ 
    public int _temp_passengers; 
    public int _passengers; 
    public int passengers 
    { 
     set { _temp_passengers = value; } 
     get { return _passengers; } 
    } 
    public void CommitState() 
    { 
     _passengers = _temp_passengers; 
    } 
} 

有一個循環,激發每X秒。每個車輛都會影響模擬中的另一輛車爲了避免每個車輛影響其他車輛時破壞屬性,我將它們存儲在一個臨時區域內,例如, _passengers。臨時值在循環結束時被提交給常規值。


的問題是以下內容:

成爲:

_temp_passengers = _passengers - 1; 

編輯:

爲了進一步解釋這一問題,想象10對車輛影響車輛甲,乘客增加1.每個乘客離開他們的車輛上車A.

所以操作passengers += 1將被稱爲10次,但它會像操作只是被稱爲一次!


  • 有一個設計模式來解決這個問題?

  • 我可以像這樣在類中包裝每個屬性嗎?

  • 我可以在set{}內添加+=-=條件嗎?

任何想法?謝謝! :)

+3

你在此刻得到了一個更大的問題 - 如果你* *獲取您的'乘客'的財產,它會炸燬,因爲它永遠遞歸... –

+2

但基本上,你只有一個領域 - 當然你需要*兩個*領域,一個e「臨時」價值,一個用於「承諾」價值。 –

+0

這是一輛普通的家用車,載着2.34名乘客(或者:你爲什麼使用'浮動')? – CodeCaster

回答

2

只需使用一種延遲執行的

public class VehicleState 
{ 
    List<Action> actionList = new List<Action>(); 

    public int passengers { get; set; } 

    public void CommitState() 
    { 
     foreach (var action in actionList) 
     { 
      action(); 
     } 
    } 

    public void Execute(Action action) 
    { 
     actionList.Add(action); 
    } 
} 

測試

[TestMethod] 
    public void MyTestMethod() 
    { 
     var vs = new VehicleState { passengers = 3 }; 
     vs.Execute(() => vs.passengers += 1); 
     Assert.AreEqual(3, vs.passengers); 
     vs.CommitState(); 
     Assert.AreEqual(4, vs.passengers); 

    } 

限制解決方案

此解決方案僅提供延遲執行。根據你的情況,這可能是有用的或不是。

var vs1 = new VehicleState { passengers = 3 }; 
var vs2 = new VehicleState { passengers = 3 }; 

vs1.Execute(() => vs1.passengers += vs2.passengers); 
// vs2.Execute(() => vs2.passengers -= vs1.passengers); // does not work 

// remember state before 
var beforeVs1passengers = vs1.passengers; 
vs2.Execute(() => vs2.passengers -= beforeVs1passengers); // that works 

vs1.CommitState(); // order might be important, no common state, no stack 
vs2.CommitState(); 
Assert.AreEqual(6, vs1.passengers); 
Assert.AreEqual(0, vs2.passengers); 
+0

謝謝!這很有趣,可能真的有用! :D – RadiantHex

+1

當然;)請注意懶惰評估的可能陷阱。我在[此博客]中找到了一個很好的示例(http://marlongrech.wordpress.com/2010/06/02/closures-in-c-can-be-evil/) – Fried

+0

感謝您的編輯!所以變量只是引用,「非工作」的例子可能會導致「vs2.passenger == -3」?我之前並不瞭解C#中的代表和事件...這非常有趣。 :) – RadiantHex

0

讓我們嘗試

public class VehicleState 
{ 
    public float _passengers; 
    public float _CommitedPassengers; 
    public float passengers 
    { 
     set { _passengers = value; } 
     get { return _passengers; } 
    } 

    public float CommitedPassengers 
    { 
     get { return _CommitedPassengers; } 
    } 

    public void CommitState() 
    { 
     _CommitedPassengers = _passengers; 

    } 
} 

我認爲這就是你所需要的

+0

感謝您的回覆!解決了我的問題,有什麼機會可以給它一個額外的外觀? :) – RadiantHex

+0

問題是'乘客+ = 1',而不必做'乘客= _temp_passengers + 1' – RadiantHex

+1

@RadiantHex如果我正確地理解你,你只是想在乘客++中執行setter?你可以,打賭最好是爲此設置一個方法 –

0

作爲對一個相當古老的問題的遲發評論 - 我不認爲「疊加屬性」在這裏很合適。您正嘗試將模型的兩種不同狀態混合到一個實例中。您已經報告了一些帶來的問題。此外,代碼將很難理解和維護。

取而代之,使用您的模型M的兩個版本,表示兩個迭代nn+1的狀態。您的計算將輸入M[n]作爲輸入,並生成/修改M[n+1]作爲輸出。

然後,您需要一種方法來從你的nextModel複製到新的狀態到currentModel

var currentModel = new Model(); 

for (var n in Enumerable.Range(0, 99)) 
{ 
    var nextModel = calculate(currentModel); 

    currentModel.UpdateFrom(nextModel); 
} 

而由Model我指的是所有車輛的整體和其他任何你模擬的一部分,並通過calculate我指的是在一次迭代中完成的全部計算。

這與您正在做的事情很接近,它只是收集您的「保留兩種狀態和以後複製」的邏輯,將其分散到一個名爲UpdateFrom的地方。具有模型的兩個實例爲您提供了一種方法,是什麼型號的狀態的計算是基於非常明確:

nextModel.Vehicles[0].passengers = 
    nextModel.Vehicles[0].passengers + currentModel.Vehicles[1].passengers 

一旦你有多個實例,你也可以選擇移動更傾向於功能的編程風格,產生在每個迭代的新模式,並扔掉舊的狀態(或保持它的記錄,如果你需要的話):

var model = new Model[100]; 
model[0] = new Model(); 

for (var n in Enumerable.Range(0, 99)) 
{ 
    // either throw away old state and keep a reference to the new state only 
    var currentModel = calculate(currentModel); 

    // or keep all states 
    model[n+1] = calculate(model[n]); 
}