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

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

问题描述

我刚刚在结构中使用异步方法遇到了一个奇怪的行为.有人可以解释为什么会这样吗,最重要的是,如果有解决办法,这是为什么?这是一个简单的测试结构,仅用于演示问题

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.async方法完成后,它已对该副本进行了突变,而您的实例结构保持不变.

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#可以发出闭合代码来执行结构 原位突变.不幸的是,对此一无所知 值在发出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).

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

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