开发者

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);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜