gpt4 book ai didi

c# - 为什么在使用异步方法时会捕获类作用域变量,而在使用 Action 时却不会(内部代码示例)?

转载 作者:可可西里 更新时间:2023-11-01 07:45:37 25 4
gpt4 key购买 nike

遛狗的时候我在想Action<T> , Func<T> , Task<T> , async/await (是的, Nerd ,我知道……)并在脑海中构建了一个小测试程序,想知道答案是什么。我注意到我不确定结果,所以我创建了两个简单的测试。

这是设置:

  • 我有一个类作用域变量(字符串)。
  • 它被分配了一个初始值。
  • 变量作为参数传递给类方法。
  • 该方法不会直接执行,而是分配给“Action”。
  • 在 Action 执行之前,我更改了变量的值。

输出结果是什么?初始值,还是更改后的值?

有点意外但可以理解,输出是改变后的值。我的解释是:在 Action 执行之前,变量不会被压入堆栈,所以它将是被改变的。

public class foo
{
string token;

public foo ()
{
this.token = "Initial Value";
}

void DoIt(string someString)
{
Console.WriteLine("SomeString is '{0}'", someString);
}

public void Run()
{
Action op = () => DoIt(this.token);
this.token = "Changed value";
// Will output "Changed value".
op();
}
}

接下来,我创建了一个变体:

public class foo
{
string token;

public foo ()
{
this.token = "Initial Value";
}

Task DoIt(string someString)
{
// Delay(0) is just there to try if timing is the issue here - can also try Delay(1000) or whatever.
return Task.Delay(0).ContinueWith(t => Console.WriteLine("SomeString is '{0}'", someString));
}

async Task Execute(Func<Task> op)
{
await op();
}

public async void Run()
{
var op = DoIt(this.token);
this.token = "Changed value";
// The output will be "Initial Value"!
await Execute(() => op);
}
}

这里我制作了DoIt()返回 Task . op现在是 Task不再是 Action . Execute()方法等待任务。令我惊讶的是,输出现在是“初始值”。

为什么它的行为不同?

DoIt()直到 Execute() 才会被执行被调用,那么为什么它会捕获 token 的初始值呢? ?

完成测试:https://gist.github.com/Krumelur/c20cb3d3b4c44134311fhttps://gist.github.com/Krumelur/3f93afb50b02fba6a7c8

最佳答案

你在这里有几个误解。首先,当您调用 DoIt 时,它会返回一个已经开始执行的任务。只有当您await Task 时,执行不会开始。

您还在 someString 变量上创建了一个闭包,当您重新分配类级字段时,它的值不会改变:

Task DoIt(string someString)
{
return Task.Delay(0).ContinueWith(t
=> Console.WriteLine("SomeString is '{0}'", someString));
}

传递给 ContinueWithActionsomeString 变量上关闭。请记住,字符串是不可变的,因此,当您重新分配token 的值时,您实际上是在分配一个新的字符串引用。但是,DoIt 中的局部变量 someString 保留了旧引用,因此即使在类字段被重新分配后其值也保持不变。

您可以通过直接在类级字段上关闭此操作来解决此问题:

Task DoIt()
{
return Task.Delay(0).ContinueWith(t
=> Console.WriteLine("SomeString is '{0}'", this.token));
}

关于c# - 为什么在使用异步方法时会捕获类作用域变量,而在使用 Action<T> 时却不会(内部代码示例)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31694842/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com