Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 关于将参数传递给返回Lambdas的方法的问题_C#_Lambda_Parameter Passing - Fatal编程技术网

C# 关于将参数传递给返回Lambdas的方法的问题

C# 关于将参数传递给返回Lambdas的方法的问题,c#,lambda,parameter-passing,C#,Lambda,Parameter Passing,(使用C#3.0和VS 2008) 在使用MVVM WPF时,您通常会编写如下属性: public bool MyProperty { get{return _myProperty;} set{ if(_myProperty == value)return; _myProperty = value; RaisePropertyChanged("MyProperty"); } } public class MyTestMet

(使用C#3.0和VS 2008)

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

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

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

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

    }
} 
进行TDD时,我通常会编写测试,例如:

[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 bool MyProperty {
    get{return _myProperty;}
    set{
        if(_myProperty == value)return;
        _myProperty = value;
        RaisePropertyChanged("MyProperty");
    }
}
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总是假的

我想也许将MakePropertyChangedHandler更改为使用ref参数会起作用

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

        return // lambda...

    }
但VisualStudio告诉我“不能在匿名方法体中使用ref或out参数“x”


有谁能告诉我是否可以编写一个像MakePropertyChangedHandler这样的工作方法,如果没有,原因是什么?

不可能为lambda提供ref,因为无法确保正确的生命周期管理。当编译器遇到闭包(lambda使用外部范围变量)时,它

  • 将所有捕获的局部变量包装到匿名对象中
  • 创建此对象的实例,而不是在堆栈上分配变量
  • 使lambda代码成为此对象的方法,并
  • 返回此对象和方法的委托
  • (细节可能有点不同,但这是原则)。这样,只要委托存在,捕获的变量就存在

    但是,当编译堆栈上方的函数时,编译器不知道这一点,因此会在堆栈上分配变量。这会更快,但是变量只在函数返回之前存在。由于闭包的寿命可能比这个长(在您的情况下不会,但编译器不知道),因此闭包不能引用堆栈变量

    您可以做的是创建一个具有引用语义的对象(只要它被引用就存在)并将其交给闭包。因此,如果您创建:

    class BoolHolder {
        public bool value;
    };
    
    把布勒霍尔德传给lambda和lambda do

    boolHolder.value = true;
    

    您将看到外部的变化。

    有关这一问题的原因,请参阅@Justin,感谢您的链接。感谢您的有益解释和解决建议。