用布尔值做保险丝

时间:2012-03-28 09:26:02

标签: c# boolean code-design

我有很多代码必须在初始化期间一次运行。

我必须以这种方式使用布尔标志,因为它处于事件

bool _fuse;

void PerformLayout()
{
    Size size;

    if (!_fuse)
    {
        size = _InitialContainerSize;
        _fuse = true;
    }
    else
        size = parent.Size;

    // ...
}

因为它经常发生,我做了一些事情来使这个布尔变量看起来像保险丝

所以我这样做了:

bool _fuse;

void PerformLayout()
{
    Size size;

    if (!Burnt(ref _fuse))
        size = _InitialContainerSize;
    else
        size = parent.Size;

    // ...
}

如果它初始化为false,则查询结果返回false一次,将切换为true,连续调用返回true。

public static bool Burnt(ref bool value)
{
    if (!value)
    {
        value = true;
        return false;
    }
    else
        return true;
}

当然,它有效,但我只是中度满意,我相信有更优雅的解决方案。你的是什么?

3 个答案:

答案 0 :(得分:1)

您可以使用可空类型和空合并运算符来声明Size属性:

Size? _containerSize;

Size ContainerSize {
  get {
    return (_containerSize ?? (_containerSize = _InitialContainerSize)).Value;
  }
}

然后您可以像这样使用它:

void PerformLayout() { 
  var size = ContainerSize;
  // ...
}

如果要延迟初始化的类型是引用类型,它会变得更简单。

另一种选择是使用Lazy<T>类型。这可用于上述代码可能破坏的多线程场景:

Lazy<Size> _containerSize = new Lazy<Size>(() => _InitialContainerSize);

void PerformLayout() { 
  var size = _containerSize.Value;
  // ...
}

答案 1 :(得分:1)

实现这一目标的方法有很多种。您可以创建一个复杂的状态机来执行您的逻辑(最快),但在许多情况下,这将是过度的。或者,您可以像现在一样跟踪保存实例状态的布尔值。您还可以决定将两种解决方案组合到一个简单的状态机中,使用类似(快速模式)的方法:

public class TestClass
{
    private Action performLayoutAction;

    public TestClass()
    {
        // initial state
        performLayoutAction = InitializePeformLayout;
    }

    public void PerformLayout()
    {
        performLayoutAction();
    }

    private void InitializePeformLayout()
    {
        // whatever 

        performLayoutAction = ContiniousPerformLayout;
    }

    private void ContiniousPerformLayout()
    {
        // whatever 
    }
} 

答案 2 :(得分:1)

我认为避免重复的一般主旨是正确的(即使重复很小......但仍然如此)。只需将其封装并正确命名即可:

struct InitializerGuard {
    private bool hasRun;

    public bool HasRun() {
        if (hasRun)
            return true;
        hasRun = true;
        return false;
    }
}

用法:

InitializerGuard sizeInitializer;

void PerformLayout()
{
    Size size;

    if (!sizeInitializer.HasRun())
        size = _InitialContainerSize;
    else
        size = parent.Size;

    // ...
}

但是如果你发现自己经常使用这种模式,这可能表明重构是有序的。也许只是为某些变量分配默认值?无论如何,他们为什么不初始化?