C# 闭包和引用设置
我想我在这里有一个基本的误解。为什么测试失败C# 闭包和引用设置,c#,reference,closures,variable-assignment,C#,Reference,Closures,Variable Assignment,我想我在这里有一个基本的误解。为什么测试失败 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
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;} }
公共静态类ObjectExtensions
{
对(此T newValue,T oldValue)的公共静态操作,其中T:class
{
return()=>oldValue=newValue;
}
}
公共静态类分配
{
公共静态T值(T值)
{
返回值;
}
}
公开课考试
{
公开无效测试()
{
var a=newtesttype{Name=“a”};
var b=“b”;
将(b)赋值给(a.Name)();
Assert.That(a.Name==“b”);//失败(a.Name==“a”)
}
}
公共类TestType{public string Name{get;set;}}
它失败,因为到
的参数是按值传递的
仅仅因为oldValue
设置为“b”,并不意味着a.Name
将被更改。在对(a.Name)的调用中,表达式a.Name
被计算为字符串引用,该引用通过值传递给方法
这是基本的。仅仅使用闭包并不能改变这一点
您可以将更改为方法,如下所示:
public static Action To<T>(this T newValue, Action<T> setter) where T : class
{
return () => setter(newValue);
}
它失败,因为到
的参数是按值传递的
仅仅因为oldValue
设置为“b”,并不意味着a.Name
将被更改。在对(a.Name)
的调用中,表达式a.Name
被计算为字符串引用,该引用通过值传递给方法
这是基本的。仅仅使用闭包并不能改变这一点
您可以将更改为方法,如下所示:
public static Action To<T>(this T newValue, Action<T> setter) where T : class
{
return () => setter(newValue);
}
换句话说,
var a = new TestType { Name = "a" };
Assign.TheValue(b).To(a.Name)();
相当于
Assign.TheValue(b).To("a")();
Convert.ToDecimal(5);
就像
int x = 5;
Convert.ToDecimal(x);
相当于
Assign.TheValue(b).To("a")();
Convert.ToDecimal(5);
换句话说,
var a = new TestType { Name = "a" };
Assign.TheValue(b).To(a.Name)();
相当于
Assign.TheValue(b).To("a")();
Convert.ToDecimal(5);
就像
int x = 5;
Convert.ToDecimal(x);
相当于
Assign.TheValue(b).To("a")();
Convert.ToDecimal(5);
为什么会变成“b”?您只是在不同的点上按值传递一个字符串ref。我的想法是:将“b”(newValue)的ref和“a”(oldValue)的ref提供给方法to,该方法将返回一个lambda,用于将newValue分配给oldValue。该lambda将由Assign.TheValue(b).To(a.Name)(;)行上的第三组括号计算;。很明显,我的理解是完全错误的。想想什么是变量。“oldValue”是一个变量。它有自己的存储空间。它不是其他变量的别名。“ref”关键字确实是变量的别名,这正是在闭包中捕获ref变量是非法的原因;因为你可以捕获一个变量,它的生存期比闭包的生存期短。谢谢Eric。你的评论使这件事的成本下降了。我对兰博达斯比较缺乏经验,这让我很失望。为什么会变成“b”?您只是在不同的点上按值传递一个字符串ref。我的想法是:将“b”(newValue)的ref和“a”(oldValue)的ref提供给方法to,该方法将返回一个lambda,用于将newValue分配给oldValue。该lambda将由Assign.TheValue(b).To(a.Name)(;)行上的第三组括号计算;。很明显,我的理解是完全错误的。想想什么是变量。“oldValue”是一个变量。它有自己的存储空间。它不是其他变量的别名。“ref”关键字确实是变量的别名,这正是在闭包中捕获ref变量是非法的原因;因为你可以捕获一个变量,它的生存期比闭包的生存期短。谢谢Eric。你的评论使这件事的成本下降了。我对lambdas比较缺乏经验,这让我很失望。我肯定我是完全愚蠢的,但我认为对lambda()的评估=>oldValue=newValue;将用新值交换对旧值的引用。我想我在这里有一个思维障碍。我想我需要重读一章关于参数传递的内容。坦白地说,这很尴尬。我肯定我是完全愚蠢的,但我认为对lambda()的评估=>oldValue=newValue;将用新值交换对旧值的引用。我想我在这里有一个思维障碍。我想我需要重读一章关于参数传递的内容。坦白说,这很尴尬。