Closures and reference setting
I think I have a fundamental misunderstanding here. Why does the test fail?
public static class ObjectExtensions
{
public static Action To<T>(this T newValue,开发者_如何转开发 T oldValue) where T : class
{
return () => oldValue = newValue;
}
}
public static class Assign
{
public static T TheValue<T>(T theValue)
{
return theValue;
}
}
public class Tests
{
public void Test()
{
var a = new TestType { Name = "a" };
var b = "b";
Assign.TheValue(b).To(a.Name)();
Assert.That(a.Name == "b"); //fails (a.Name == "a")
}
}
public class TestType { public string Name {get;set;} }
It fails because the arguments to To
are passed by value.
Just because oldValue
is set to "b" doesn't mean that a.Name
will be changed at all. In the call To(a.Name)
, the expression a.Name
is evaluated to a string reference, and that reference is passed to the method by value.
That's basic parameter passing in C#. Just using a closure doesn't change that.
What you can do is change the To
method like this:
public static Action To<T>(this T newValue, Action<T> setter) where T : class
{
return () => setter(newValue);
}
then change the call to:
Assign.TheValue(b).To(x => a.Name = x)();
Put another way,
var a = new TestType { Name = "a" };
Assign.TheValue(b).To(a.Name)();
is equivalent to
Assign.TheValue(b).To("a")();
just like
int x = 5;
Convert.ToDecimal(x);
is equivalent to
Convert.ToDecimal(5);
精彩评论