【问题标题】:How do I automatically reset a boolean when any method other is called in C#?当在 C# 中调用任何其他方法时,如何自动重置布尔值?
【发布时间】:2010-04-12 23:03:41
【问题描述】:

使用 C#,如果函数 A() 在函数 C() 之前被调用,我需要做一些额外的工作。如果在A()C() 之间调用了任何其他函数,那么我不想做那些额外的工作。有什么想法需要最少的代码重复?

我试图避免在每个函数 B1..BN 中添加像 flag = false; 这样的行。

这是一个非常基本的例子:

bool flag = false;

void A()
{
    flag = true;
}

void B1()
{
    ...
}

void B2()
{
    ...
}

void C()
{
    if (flag) 
    {
        //do something
    }
}

上面的例子只是使用了一个简单的案例,但我愿意使用布尔值以外的东西。重要的是我希望能够设置和重置各种标志,以便C() 知道如何相应地表现。

感谢您的帮助。如果您需要澄清,我将编辑我的帖子。

【问题讨论】:

  • 多个线程会调用A吗?即这需要是线程安全的吗?

标签: c# set call flags


【解决方案1】:

为什么不将您的“额外工作”纳入一个记忆函数(即缓存其结果的函数)?每当您需要这项工作时,您只需调用此函数,如果缓存是新的,它将短路。每当该工作变得陈旧时,就使缓存无效。在上面你相当奇怪的例子中,我假设你需要在每个 B 中调用一个函数,在 C 中调用一个函数。调用 A 将使缓存无效。

如果您正在寻找周围的东西(即一些巧妙的方法来捕获所有函数调用并插入此调用),我真的不会打扰。我可以设想一些疯狂的运行时反射代理类生成,但你应该让你的代码流清晰明了;如果每个函数都依赖于已经完成的工作,只需在每个函数中调用“doWork”即可。

【讨论】:

  • 是的,我认为没有简单的方法可以做到这一点。可以按任何顺序调用函数。只有 A(),C() 的特定顺序需要额外的工作,但是如果我在 A() 中设置一个标志并且在调用 B1() 或 B2() 时不重置它,那么在 C()我得到了不正确的行为。
  • +1 参考反射;对于“疯狂”的标签,在这种情况下非常准确;)
【解决方案2】:

如果调用一种方法会改变另一种方法的行为,那么您的设计似乎过于紧密耦合,因此您必须确保以正确的顺序调用它们。这是一个重要的危险信号。

听起来有些重构是有序的。在没有看到更多真实代码的情况下给出建议有点棘手,但这是正确方向的一点。

考虑像这样向 C 中添加一个参数:

void C(bool DoExtraWork) {
  if (DoExtraWork)...
}

当然,“DoExtraWork”应该在调用者的上下文中命名为有意义的东西。

【讨论】:

  • 我见过类似的编码模式,在某些情况下,它们是合理的。毕竟,方法的行为取决于其类的状态合理的:P
【解决方案3】:

我通过一个简单的状态机解决了一个类似情况的问题(即需要知道 A 是否在 C 之前被直接调用)。本质上,我使用 enum 和属性构建了一个状态对象来管理/查询状态。

当我的 A() 等价物被调用时,它将使业务逻辑块存储在指示 A 被调用的状态之外。如果调用了其他方法(你的 B 的),它会将状态切换到其他几个状态之一(我的情况有点复杂),然后当 C() 被调用时,查询业务逻辑片段以确定我们是否将调用一些方法 D(),该方法具有“仅当 A 被调用时”功能。

我怀疑有多种方法可以解决这个问题,但我喜欢我采用的状态机方法,因为它允许我扩展最初的二元情况以处理更复杂的多状态情况。

我很幸运,多线程在我的情况下不是问题,因为这往往会使事情变得更有趣,但状态机也可能在这种情况下工作。

只要我的两分钱。

【讨论】:

  • 事实证明我能够使用类似的方法解决它。我使用了一个枚举并找到了一个更简洁的解决方案,它不需要耦合函数 A() 和 C()。
【解决方案4】:

我不建议这样做,但到底是什么:如果您愿意替换所有简单的方法调用:

A();

... 语法如下:

// _lastAction is a class-level Action member
(_lastAction = new Action(A)).Invoke();

...然后在C() 内部,您可以像这样进行检查:

void C()
{
    if (_lastAction.Method.Name == "A")
    {

    }
}

这可能不是线程安全的(如果没有一点修补,它在通过混淆器运行的代码中是行不通的),所以我不会在没有大量测试的情况下使用这样的东西。我也不会使用这种时期的东西。

注意:我的古代 C# 版本只有 Action<T>(而不是 ActionAction<T, T> 等),所以如果你也卡在那里,你必须为每个添加一个虚拟参数使用这种方法的方法。

【讨论】:

  • 我同意这种东西很混乱。我当时只是没有想到一个好的解决方案,但我找到了一个没有混乱的解决方案。感谢您的努力。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-07
  • 2021-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-26
相关资源
最近更新 更多