有关将参数传递给返回Lambda的方法的问题 [英] Question About Passing Parameters To Methods That Return Lambdas

查看:67
本文介绍了有关将参数传递给返回Lambda的方法的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(使用C#3.0和VS 2008).

(with C# 3.0 and VS 2008).

在进行MVVM WPF时,您通常会编写如下属性:

Doing MVVM WPF stuff you often write properties like this:

public bool MyProperty {
    get{return _myProperty;}
    set{
        if(_myProperty == value)return;
        _myProperty = value;
        RaisePropertyChanged("MyProperty");
    }
}

做TDD时,我经常会写如下测试:

Doing TDD I often end up writing tests such as:

[Test]
public void MyPropertyRaisesPropertyChangedWhenChanged(){
    var mySUT = CreateSUT();

    bool eventRaised = false;
    string propName = "";

    mySUT.PropertyChanged += 
        (s,e)=>{eventRaised = true;propName = e.PropertyName;};

    Assert.That(mySUT.MyProperty,Is.False(),"mySUT.MyProperty");

    mySUT.MyProperty = true;

    Assert.That(eventRaised,"eventRaised");
    Assert.That(propName, Is.EqualTo("MyProperty"),"propName");

    // could check not raised when set same...
}

我尝试了这样的方法:

public class MyTestMethods{

    public static PropertyChangedEventHandler MakePropertyChangedHandler(
        bool eventWasRaised, string propertyName){    

        return (s,e)=>{eventWasRaised = true; propertyName = e.PropertyName};

    }
} 

以便我可以编写测试:

[Test]
    public void MyPropertyRaisesPropertyChangedWhenChanged(){
        var mySUT = CreateSUT();

        bool eventRaised = false;
        string propName = "";

        mySUT.PropertyChanged += 
            MyTestMethods.MakePropertyChangedHandler(eventRaised,propName);

        // etc...
}

但是VS2008告诉我,eventRaised永远是错误的.

But VS2008 told me that eventRaised would always be false.

我认为也许更改MakePropertyChangedHandler以使用ref参数会起作用

I thought maybe changing MakePropertyChangedHandler to use ref parameters would work

    public static PropertyChangedEventHandler MakePropertyChangedHandler(
        ref bool eventWasRaised, ref string propertyName){

        return // lambda...

    }

但是VisualStudio告诉我'不能在匿名方法主体中使用ref或out参数'x'.

but VisualStudio tells me 'Cannot use ref or out parameter 'x' inside an anonymous method body'.

任何人都可以告诉我是否可以编写一个像MakePropertyChangedHandler这样的工作方法,如果不能,怎么来?

Can anyone tell me if it's possible to write a working method like MakePropertyChangedHandler and if not, how come?

推荐答案

由于无法确保适当的生命周期管理,因此无法对lambda进行引用.当编译器遇到闭包(使用外部作用域变量的lambda)时,

It's not possible to give ref to a lambda, because proper life cycle management can't be ensured. When the compiler encounters a closure (lambda using outer scope variable), it

  1. 将所有捕获的局部变量包装在一个匿名对象中,
  2. 创建此对象的实例,而不是在堆栈上分配变量,
  3. 使lambda代码成为该对象的方法,并且
  4. 将委托返回给该对象和方法

(细节可能有所不同,但这是原理).这样,捕获的变量就和委托一样存在.

(details might be a bit different, but that's the principle). This way the captured variables exist as long as the delegate does.

但是,当在堆栈上方编译函数时,编译器不知道这一点,因此会在堆栈上分配变量.这样更快,但是变量仅在函数返回之前存在.由于闭包的生存期可以长于此时间(在您的情况下,它不会,但是编译器不知道),因此闭包不能引用堆栈变量.

However when compiling the function higher up the stack, the compiler does not know this and so it allocates variables on the stack. That's faster, but the variables only exist until the function returns. Since the closure can live longer than that (in your case it won't, but the compiler can't know), the closure can't refer to the stack variable.

您可以做的是创建一个具有引用语义的对象(该对象在被引用之前就存在),并将其提供给闭包.因此,如果您创建:

What you can do is create an object with reference semantics (which lives as long as it's refered to) and give it to the closure. So if you create:

class BoolHolder {
    public bool value;
};

将BoolHolder传递给lambda,然后在lambda中传递

pass BoolHolder to the lambda and in the lambda do

boolHolder.value = true;

然后您会在外面看到变化.

than you'll see the change outside.

这篇关于有关将参数传递给返回Lambda的方法的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆