我正在使用一个开关作为我的XNA游戏的状态管理器。该开关是主更新方法的一部分,因此它每帧都运行。有时我需要设置一个计时器值,它应该只为每个方法调用设置一次。有多种方法可以设置每个案例的计时器,因此它不能使用当前和以前的状态数来检查是否可以覆盖以前的时间。
case "state 34": {
SetTime(theTime); // should run only once
// other things
if (TheTimeisRight(time)) // runs every call
{
SetTime(theTime); // should run only once
if (TheTimeisRight(time))
{ /* some methods */ }
}
break; }
如何才能完成这项工作,或者有更好的方法可以在不离开交换机的情况下完成此操作? (改变SetTime方法是可以的,但我不想用额外的代码弄乱开关)
答案 0 :(得分:1)
另一种方法:在你想要调用的方法周围引入一个包装器:
public sealed class RunOnceAction
{
private readonly Action F;
private bool hasRun;
public RunOnceAction(Action f)
{
F = f;
}
public void run()
{
if (hasRun) return;
F();
hasRun = true;
}
}
然后在switch语句之前创建var setTimeOnce = new RunOnceAction(() => SetTime(theTime));
,并将其作为setTimeOnce.run()
调用。根据需要调整参数/返回值。
答案 1 :(得分:0)
将呼叫置于循环外。
您可能需要一个单独的条件语句来确定它是否应该运行,但这必须比尝试使用标志和/或各种其他恶臭代码方法来控制重复的调用要好得多。
修改强>
这就是我把它放在交换机外的一个地方中的意思:
if (someCondition && someOtherCondition && yetAnotherCondition)
setTime(theTime); // just one call, in one place, gets executed once
switch(someValue)
{
case "state 34": {
//SetTime(theTime); // no longer necessary
// other things
if (TheTimeisRight(time)) // runs every call
{
//SetTime(theTime); // no longer necessary
if (TheTimeisRight(time))
{ /* some methods */ }
}
break;
...etc...
}
建议:使用枚举作为开关值而不是字符串。
粗暴地说,这就像任何人都可以在没有看到更完整的代码示例的情况下实际地帮助你(我认为你给我们的样本有点做作,而且对你的内容不太准确)。有可能解决这个问题的最好方法是解构switch语句并重新开始,因为维护状态机不是处理这种情况的最佳方法,或者你需要引入其他一些状态。
答案 2 :(得分:0)
如果你不想搞乱布尔变量ala hasSetTimeAlready
,你总是可以引入另一个调用方法的状态,然后进入原始状态。
答案 3 :(得分:0)
我已经使用HashSet<int>
检查之前是否使用SetTime(time, num)
调用了当前的if (!hashSet.Contains(num))
方法。
void SetTime(int time, int num)
{
if (!hashSet.Contains(num))
{
theTime = time;
hashSet.Add(num);
}
}
当然看起来并不太酷,但是工作并且它不会过多地损害方法调用(视觉上),因此保存了开关的可读性。