Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

198
Visualizações
Struct's private field value is not updated using an async method

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);

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?

over 4 years ago · Santiago Trujillo
1 Respostas
Responde à pergunta

0

Why?

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

This is what ChangeAsync actually looks like:

[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;
}

The important line is this:

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

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.

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.

Edit:

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.

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).

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda