结构的私有字段值未使用异步方法更新 [英] Struct's private field value is not updated using an async method

查看:20
本文介绍了结构的私有字段值未使用异步方法更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚在结构中使用异步方法时遇到了一个奇怪的行为.有人可以解释为什么会发生这种情况,最重要的是是否有解决方法?这里有一个简单的测试结构,只是为了演示问题

I just came across a strange behavior with using async methods in structures. Can somebody explain why this is happening and most importantly if there is a workaround? Here is a simple test structure just for the sake of a demonstration of the problem

public struct Structure 
{
   private int _Value;

   public Structure(int iValue) 
   {
      _Value = iValue;
   }

   public void Change(int iValue)
   {
      _Value = iValue;
   }

   public async Task ChangeAsync(int iValue)
   {
      await Task.Delay(1);
      _Value = iValue;
   }
}

现在,让我们使用该结构并执行以下调用

Now, let's use the structure and do the following calls

var sInstance = new Structure(25);
sInstance.Change(35);
await sInstance.ChangeAsync(45);

第一行实例化结构,sInstance._Value 值为 25.第二行更新了 sInstance._Value 值,它变成了 35.现在第三行没有做任何事情,但我希望它将 sInstance._Value 值更新为 45 但是 sInstance._Value 保持 <代码>35.为什么?有没有办法为结构编写异步方法并更改结构字段的值?

The first line instantiates the structure and the sInstance._Value value is 25. The second line updates the sInstance._Value value and it becomes 35. Now the third line does not do anything but I would expect it to update the sInstance._Value value to 45 however the sInstance._Value stays 35. Why? Is there a way to write an async method for a structure and change a structure field's value?

推荐答案

为什么?

因为您的 struct 被提升到状态机上的方式.

Because of the way your struct is lifted onto the state machine.

这就是 ChangeAsync 实际上的样子:

[DebuggerStepThrough, AsyncStateMachine(typeof(Program.Structure.<ChangeAsync>d__4))]
public Task ChangeAsync(int iValue)
{
    Program.Structure.<ChangeAsync>d__4 <ChangeAsync>d__;
    <ChangeAsync>d__.<>4__this = this;
    <ChangeAsync>d__.iValue = iValue;
    <ChangeAsync>d__.<>t__builder = AsyncTaskMethodBuilder.Create();
    <ChangeAsync>d__.<>1__state = -1;
    AsyncTaskMethodBuilder <>t__builder = <ChangeAsync>d__.<>t__builder;
    <>t__builder.Start<Program.Structure.<ChangeAsync>d__4>(ref <ChangeAsync>d__);
    return <ChangeAsync>d__.<>t__builder.Task;
}

重要的一行是:

<ChangeAsync>d__.<>4__this = this;

编译器将你的结构的一个副本提升到它的状态机中,有效地用值 45 更新它的副本.当异步方法完成时,它已经改变了副本,而你的实例结构保持不变.

The compiler lifts a copy of your struct into its state-machine, effectively updating its copy with the value 45. When the async method completes, it has mutated the copy, while the instance of your struct remains the same.

这是处理可变结构时的预期行为.这就是为什么他们倾向于邪恶.

This is somewhat an expected behavior when dealing with mutable structs. That's why they tend to be evil.

你是如何解决这个问题的?由于我没有看到这种行为发生变化,因此您必须创建一个 class 而不是 struct.

How do you get around this? As I don't see this behavior changing, you'll have to create a class instead of a struct.

将此作为问题发布在 GitHub 上.收到来自@AlexShvedov 的受过良好教育的回复,其中更深入地解释了结构和状态机的复杂性:

Posted this as an issue on GitHub. Received a well educated reply from @AlexShvedov, which explains a bit deeper the complexity of structs and state machines:

由于每个闭包的执行都可以任意延迟,我们需要某种方式也可以延迟所有被俘虏的成员的生命周期关闭.对于这种值类型,一般没有办法做到这一点,因为值类型可以在堆栈上分配(值的局部变量类型)和堆栈空间将在方法执行退出时重用.

Since execution of every closure can be arbitrarily delayed, we need some way to also delay the lifetime of all the members captured into closure. There is no way to do it in general for this of value type, since value type can be allocated on stack (local variables of value types) and stack space will be reused on method execution exit.

理论上,当值类型存储为某个托管的字段时数组的对象/元素,C# 可以发出闭包代码来做结构体原地突变.不幸的是,不知道这在哪里value 是在发出 struct 成员代码时定位的,所以 C# 决定只是为了强制用户手动处理这种情况(通过复制大多数情况下都是这个值,正如错误消息所建议的那样).

In theory, when value type is stored as a field of some managed object/element of array, C# can emit closure code to do struct mutation inplace. Unfortunately, there is no knowledge on where this value is located when emitting struct member code, so C# decided simply to force users handle this situation manually (by copying the this value most of the time, as error message suggested).

这篇关于结构的私有字段值未使用异步方法更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆