2013-07-29 84 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]); 
}