Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.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# 闭包和引用设置_C#_Reference_Closures_Variable Assignment - Fatal编程技术网

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;将用新值交换对旧值的引用。我想我在这里有一个思维障碍。我想我需要重读一章关于参数传递的内容。坦白说,这很尴尬。