How to deal with side effects produced by async/await when it comes to mutable value types?

前端 未结 1 460
长情又很酷
长情又很酷 2021-01-04 09:21

Please, consider the following example code:

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

public struct AStruct
{
    public int Value;

    publ         


        
相关标签:
1条回答
  • 2021-01-04 09:31

    It's inherently impossible for an async method of a struct to mutate "itself".

    This of course makes complete sense when you think about it. By the time the whatever tasks you await inside of that struct actually finish, given that you've returned to the caller and allowed them to continue on doing all sorts of things, you have no way of ensuring that the actual struct instance that called the method even exists any more. If SetValueAsync was called on a local variable by a method that didn't await it or Wait on it or anything like that then that local variable's lifetime will likely have ended by the time SetValueAsync reaches the continuation of it's call to Run. It can't mutate the variable who's lifetime may or may not be in scope. The only option here is for async methods of a struct to effectively copy themselves when the method is called and have the code in the continuation reference an entirely different variable that the variable that called the async. Since the method is making a copy that won't be accessible anywhere other than the body of this async method, it means that, for all intents an purposes, an async method of a struct can never mutate that struct (and have the mutation be visible by anyone else).

    You can have an async method of a mutable struct, so long as that method itself isn't expected to mutate the struct. That one method will need to return a Task<T> with a new struct, or something equivalent.

    As an interesting tanget, it's within the bounds of technical possibility for an async method of a struct to mutate itself before the first await of the method if it really wanted to. The compiler chooses to take the copy right away, so this isn't actually possible, but the explicit choice was made to make the copy at the very start of the method rather than only after the first await. This is probably for the best, whether it was an intentional decision or not, as it would be super confusing otherwise.

    0 讨论(0)
提交回复
热议问题