gpt4 book ai didi

c# - 当涉及到可变值类型时,如何处理 async/await 产生的副作用?

转载 作者:可可西里 更新时间:2023-11-01 08:25:29 24 4
gpt4 key购买 nike

请考虑以下示例代码:

using System.Diagnostics;
using System.Threading.Tasks;

public struct AStruct
{
public int Value;

public async Task SetValueAsync()
{
Value = await Task.Run(() => 1);
}
public void SetValue()
{
Value = 1;
}
}

class Program
{
static void Main(string[] args)
{
Test(new AStruct());
TestAsync(new AStruct()).Wait();
}

private static async Task TestAsync(AStruct x)
{
Debug.Assert(x.Value == 0);
await x.SetValueAsync();
Debug.Assert(x.Value == 0);
}

private static void Test(AStruct x)
{
Debug.Assert(x.Value == 0);
x.SetValue();
Debug.Assert(x.Value == 1);
}
}

请注意 TestTestAsync 之间的区别。此代码满足所有断言。

我想用 Reflector 查看代码会告诉我原因,但这仍然是我完全没想到的事情。

当然,将 AStruct 更改为类而不是结构确实会使 TestAsync 中的第二个断言失败 - 正如我首先期望的那样。

我的问题是 - 除了不将可变结构与 async/await 一起使用之外,是否有一种优雅的方式让它们和平共存?

最佳答案

async 本质上是不可能的struct 的方法变异“自身”。

当您考虑时,这当然是完全有道理的。到时候你有什么任务await在该结构内部实际上完成了,假设您已经返回给调用者并允许他们继续做各种事情,您无法确保调用该方法的实际结构实例甚至不再存在。如果SetValueAsync被一个没有 await 的方法调用到局部变量它或Wait在它或类似的东西上,那么局部变量的生命周期可能会在 SetValueAsync 时结束。到达它对 Run 的调用的延续.它不能改变生命周期可能在范围内或不在范围内的变量。这里唯一的选择是 async结构的方法在调用方法时有效地复制自身,并让延续中的代码引用一个与调用 async 的变量完全不同的变量。 .由于该方法正在制作一个副本,除此 async 的正文外,其他任何地方都无法访问该副本。方法,这意味着,出于所有目的,一个async结构的方法永远不能改变该结构(并且改变对其他任何人可见)。

你可以有一个 async可变方法 struct ,只要该方法本身不会改变 struct .该方法需要返回 Task<T>使用新的结构或类似的东西。

作为一个有趣的切线,它在 async 的技术可能性范围内struct 的方法在第一个 await 之前改变自己的方法 如果它真的想要的话。编译器选择立即获取副本,所以这实际上是不可能的,但明确选择在方法的最开始制作副本,而不是仅在第一个 await 之后制作副本。 .这可能是最好的选择,无论它是否是有意的决定,否则会非常困惑。

关于c# - 当涉及到可变值类型时,如何处理 async/await 产生的副作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24811287/

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