(使用C#3.0和VS 2008)。
做MVVM WPF的东西你经常写这样的属性:
public bool MyProperty {
get{return _myProperty;}
set{
if(_myProperty == value)return;
_myProperty = value;
RaisePropertyChanged("MyProperty");
}
}
做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 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这样的工作方法,如果没有,怎么回事?
答案 0 :(得分:2)
不可能将ref赋予lambda,因为无法确保正确的生命周期管理。当编译器遇到闭包(使用外部作用域变量的lambda)时,它
(细节可能有点不同,但这是原则)。这样,只要代理人就可以存在捕获的变量。
然而,当编译函数在堆栈的更高位置时,编译器不知道这一点,因此它在堆栈上分配变量。这更快,但变量只存在,直到函数返回。由于闭包可以活得比那个(在你的情况下它不会,但编译器无法知道),闭包不能引用堆栈变量。
你可以做的是创建一个带引用语义的对象(只要它被引用就存在)并将它交给闭包。所以如果你创建:
class BoolHolder {
public bool value;
};
将BoolHolder传递给lambda并在lambda中传递
boolHolder.value = true;
比你看到外面的变化。