【问题标题】:Lambda closure or class level variable?Lambda 闭包或类级别变量?
【发布时间】:2009-01-08 15:46:30
【问题描述】:

关于最佳实践是什么的一般性问题:

public void Foo()
{
    int x = 5;
    myControl.Click += (o, e) =>
    {
        x = 6;
    };
}

注意,我在我的 lambda 事件处理程序中使用了 x 变量。

或者:

public class Bar
{
    private int x = 5;
    public void Foo()
    {
        Control myControl = new Control();
        myControl.Click += new EventHandler(myControl_Click);
    }

    private void myControl_Click(object sender, EventArgs e)
    {
        x = 6;
    }
}

这里,x 是该类的私有成员,因此我可以在我的事件处理程序中访问它。

现在假设我在代码中的其他任何地方都不需要x(无论出于何种原因),哪种方法更好?

【问题讨论】:

  • 我不习惯那种关闭的东西,我想我不明白...第一种方式,当 myControl.Click 被触发并且没有 x 时会发生什么范围( Foo() 已返回)?
  • 幕后发生的事情是私有类是用 x 作为实例变量创建的。在这种情况下,x 被复制到私有类。没有副作用,因为 x 是该方法的本地范围。

标签: c# lambda closures variable-declaration


【解决方案1】:

这取决于您的需要。在第一个示例中,事件处理程序的副作用仅限于方法范围,而在第二个示例中,副作用仅限于实例范围。我认为在您的第一个示例中使用闭包没有任何意义,因为 X 没有在任何地方使用,因此很难根据您的示例来确定。

话虽如此,通常最好将事件处理程序(您在代码中创建的)视为变量。尽可能缩小它们的范围,并根据需要将它们重构为更广泛的范围。

当你应该使用闭包时,一个更好的例子强调如下:

public void Subscribe(Action<string> messageCallBack)
{
    myButton.Click += () => messageCallBack("Button was clicked.");
}

这允许多个订阅者,并且比替代方案简单得多:

private readonly List<Action<string>> callBacks;
public MyClass()
{
    callBacks = new List<Action<string>>();
    myButton.Click += myButton_Click;
}

private myButton_Click(object sender, EventArgs e)
{
    foreach (Action<string> callBack in callBacks)
    {
        callBack("Button was clicked");
    }
}

public void Subscribe(Action<string> messageCallBack)
{
    callBacks.Add(messageCallBack);
}

【讨论】:

    【解决方案2】:

    如果您在代码中的其他任何地方都不需要 x,则您的处理程序是无操作的 - 所以这肯定是一种无意义的情况。

    一旦你确实需要 x,你需要决定它是否应该被限定为 Bar 实例或委托实例(或者可能是一些委托集合),这将决定你做什么。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-22
      • 2010-11-06
      • 2018-10-01
      • 2018-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多