<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pedro Jesus</title>
    <description>The latest articles on DEV Community by Pedro Jesus (@jesus).</description>
    <link>https://dev.to/jesus</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F671807%2Fed81f50e-7d5d-4cf3-9612-e1c323b7acc3.jpeg</url>
      <title>DEV Community: Pedro Jesus</title>
      <link>https://dev.to/jesus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jesus"/>
    <language>en</language>
    <item>
      <title>ArrayPool</title>
      <dc:creator>Pedro Jesus</dc:creator>
      <pubDate>Fri, 23 Jan 2026 11:34:15 +0000</pubDate>
      <link>https://dev.to/jesus/arraypool-ail</link>
      <guid>https://dev.to/jesus/arraypool-ail</guid>
      <description>&lt;h3&gt;
  
  
  Introdução
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Pooling&lt;/em&gt; é uma estratégia utilizada na programação para reduzir os custos de alocação de certos objetos, que podem ser muito caros para criar e/ou finalizar. Dentro da BCL do .NET existem poucos tipos de &lt;em&gt;pool&lt;/em&gt;, sendo os mais famosos o &lt;code&gt;ThreadPool&lt;/code&gt; e &lt;code&gt;ArrayPool&lt;/code&gt;. Quando usado corretamente, essa estratégia pode ajudar na performance do software; porém, quando usado incorretamente, pode degradar a performance ou deixar o código mais complexo sem alterar o funcionamento do software.&lt;/p&gt;

&lt;p&gt;Além dos &lt;em&gt;pools&lt;/em&gt; inclusos na BCL do .NET, é possível criar sua própria estratégia de &lt;em&gt;pooling&lt;/em&gt;. Caso queira seguir um padrão e não sabe por onde começar, o pacote &lt;a href="https://www.nuget.org/packages/Microsoft.Extensions.ObjectPool" rel="noopener noreferrer"&gt;Microsoft.Extensions.ObjectPool&lt;/a&gt; é uma ótima alternativa.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Eu sugiro que você implemente pelo menos um &lt;em&gt;pooling&lt;/em&gt; na vida, para ter uma noção. Isso é algo que tem grandes chances de você usar na sua carreira.&lt;br&gt;
Sugiro também, que esse primeiro &lt;em&gt;pooling&lt;/em&gt; seja um ArrayPool, depois que fizer e garantir que ele funciona, dê uma olhada na implementação do .NET, ficou muito diferente? Aprendeu algo novo? &lt;a href="https://github.com/dotnet/dotnet/blob/main/src/runtime/src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.cs" rel="noopener noreferrer"&gt;Implementação&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Esse é mais um artigo que escrevo motivado pela quantidade de baboseiras que vejo na internet, principalmente no LinkedIn, sobre o quanto todas as pessoas que desenvolvem com .NET deveriam usar o &lt;code&gt;ArrayPool&lt;/code&gt; em vez de &lt;code&gt;new T[]&lt;/code&gt;. Espero que ao final desse artigo você perceba que essa ferramenta não pode ser utilizada em qualquer lugar e das problemáticas existentes em simplesmente sair usando o &lt;code&gt;ArrayPool&lt;/code&gt; sem pensar.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Na real, sempre fique com um pé atrás em relação a qualquer "dica" que você veja no LinkedIn.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Usando o ArrayPool
&lt;/h3&gt;

&lt;p&gt;E sem mais delongas vamos ao básico, como usar o ArrayPool?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Buffers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ArrayPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Rent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Utilizar o array&lt;/span&gt;

&lt;span class="n"&gt;ArrayPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Provavelmente você quer isso dentro do finally.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com isso, poderia-se afirmar: E simples assim, foi obtido um array de bytes com tamanho de 20 para ser utilizado sem alocação real. Como já dizia o poeta, nem tudo que brilha é ouro.&lt;/p&gt;

&lt;p&gt;Se você fizer &lt;code&gt;Console.WriteLine(buffer.Length)&lt;/code&gt; a saída será 32, ou seja, pedimos por um array de tamanho 20 e recebemos um array de tamanho 32. O motivo para isso é bem simples, o ArrayPool guarda arrays com tamanho de base 2 (2, 4, 8, 16, etc) então ele vai te retornar um array que tenha pelo menos o valor requisitado.&lt;/p&gt;

&lt;p&gt;A outra afirmativa, que pode gerar confusão é o "sem alocação real". Existe uma alocação sim, o &lt;code&gt;ArrayPool&lt;/code&gt; cria novos arrays sob demanda. Então, se não existir um com o valor desejado, ele será criado e disponibilizado. Se esse array nunca voltar para o &lt;em&gt;pool&lt;/em&gt; outro será criado, neste cenário sempre será alocado um novo array. Agora que aprendemos a usar, basicamente, vamos as armadilhas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custo de uso de um pool
&lt;/h2&gt;

&lt;p&gt;Como eu disse, nem sempre essa estratégia de &lt;em&gt;pooling&lt;/em&gt; é efetiva. Quando o objeto é muito pequeno, é mais barato deixar o GC lidar com isso. Por conta disso o menor array possível de se obter do &lt;code&gt;ArrayPool&lt;/code&gt; é de tamanho 16. Com isso, se o cenário precisar de um array menor do que isso é melhor nem usar o &lt;code&gt;ArrayPool&lt;/code&gt;, e dependendo de como você usar, o JIT pode otimizar e manter o &lt;code&gt;array&lt;/code&gt; na memória stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  ArrayPool pode te entregar array com lixo
&lt;/h3&gt;

&lt;p&gt;Se o &lt;em&gt;software&lt;/em&gt; está rodando há bastante tempo e fazendo uso do &lt;code&gt;ArrayPool&lt;/code&gt;, é bem provável que ele te entregue arrays com lixo de memória. Isso acontece pelo fato do &lt;code&gt;ArrayPool&lt;/code&gt; não limpar os arrays, por padrão, quando são devolvidos. Além disso, ao alocar novos arrays, eles podem não estar zerados, para ter um ganho de performance. Para ilustrar melhor, olhe o seguinte cenário:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ArrayPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Rent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// buffer.Length == 64&lt;/span&gt;

&lt;span class="nf"&gt;ProcessMessageFromDevice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Vai preencher do índice 0 a 41&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;SendToController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// vai percorrer do índice 0 a 63&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;ArrayPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consegue ver o problema? Exatamente, o &lt;code&gt;foreach&lt;/code&gt; vai percorrer todo o array, ou seja, todas as 64 posições. Até o índice 41 é garantido que os dados estarão de acordo com as regras de negocio, mas depois desse índice não existe garantia. Como se resolve isso? Pode-se usar um &lt;code&gt;for&lt;/code&gt; ou &lt;code&gt;while&lt;/code&gt;, ou manter o &lt;code&gt;foreach&lt;/code&gt; e usar o &lt;code&gt;Take(n)&lt;/code&gt; do LINQ.&lt;/p&gt;

&lt;h3&gt;
  
  
  ArrayPool pode causar memory leak
&lt;/h3&gt;

&lt;p&gt;Em alguns casos o uso de ArrayPool pode causar &lt;em&gt;memory leak&lt;/em&gt;, a ideia de se ter um &lt;em&gt;pool&lt;/em&gt; é manter o(s) objeto(s) vivo(s), isso também é válido para os tipos que eles seguram. Em outras palavras, se o array tiver um &lt;code&gt;ReferenceType&lt;/code&gt; ou um &lt;code&gt;ValueType&lt;/code&gt; que tenha um &lt;code&gt;ReferenceType&lt;/code&gt; isso vai causar um &lt;em&gt;memory leak&lt;/em&gt;, se for apenas &lt;code&gt;ValueType&lt;/code&gt; não vai ocorrer um leak, no caso dos exemplos aqui &lt;code&gt;ArrayPool&amp;lt;byte&amp;gt;&lt;/code&gt; não vai ter esse problema. Agora se for algo do tipo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;//ReferenceType&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Batata&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//ValueType que aponta para um ReferenceType&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Banana&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Banana&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;buffer1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ArrayPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Batata&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Rent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;buffer2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ArrayPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Banana&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Rent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;buffer1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;buffer2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;ArrayPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Batata&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;ArrayPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Banana&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse caso, quando retornar para o &lt;em&gt;pool&lt;/em&gt; o array vai existir e manterá referências fortes para os objetos &lt;code&gt;Batata&lt;/code&gt; e &lt;code&gt;Banana&lt;/code&gt;, causando assim um &lt;em&gt;memory leak&lt;/em&gt;, pois o GC não marcará esses objetos para serem coletados.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No caso da struct, o objeto que vai causar o &lt;em&gt;memory leak&lt;/em&gt; é a &lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;E como resolver isso? Limpando o array durante a devolução, o método return aceita um &lt;code&gt;bool&lt;/code&gt; para indicar se o array deve ser limpo ou não. Para evitar o &lt;em&gt;memory leak&lt;/em&gt; basta trocar as duas últimas linhas por:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;ArrayPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Batata&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clearArray&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;ArrayPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Banana&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clearArray&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mas vem a pergunta, por que o padrão não é limpar o array sempre ao devolver? Porque fazer essa limpeza pode afetar a performance negativamente ( O(n) ), então por isso os valores não são limpos, e esse gerenciamento fica a cargo de quem os utiliza. Também numa base de código grande isso pode ficar complicado de gerenciar, então se tiver dúvidas ou dependendo do cenário de uso, é possível deixar essa decisão para o &lt;em&gt;runtime&lt;/em&gt;, com o método &lt;code&gt;RuntimeHelpers.IsReferenceOrContainsReferences&amp;lt;T&amp;gt;()&lt;/code&gt;. &lt;a href="https://github.com/Cysharp/ZLinq/blob/c6d15be4efecc0afca628fd194f8f62ee0b4bb15/src/ZLinq/Internal/RentedArrayBox.cs#L34" rel="noopener noreferrer"&gt;Aqui&lt;/a&gt; você consegue ver um exemplo de uso, na biblioteca &lt;code&gt;ZLinq&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Não deixar o array sair do escopo
&lt;/h3&gt;

&lt;p&gt;O array obtido pelo &lt;code&gt;ArrayPool&lt;/code&gt; não deve sair do escopo do método que está sendo usado. Ou seja, dar um &lt;code&gt;return&lt;/code&gt; no array vai tornar ainda mais difícil devolvê-lo, fazendo com que o propósito do &lt;em&gt;pool&lt;/em&gt; não seja cumprido.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ArrayPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Rent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;Compute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Como esse array vai ser devolvido?&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Não fica claro para quem consome o método &lt;code&gt;Do&lt;/code&gt; que o array veio de um &lt;em&gt;pool&lt;/em&gt;, então, provavelmente, ele não será retornado para o &lt;em&gt;pool&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Não é uma boa prática retornar qualquer array para o pool, se for um array inválido uma exception será lançada.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Agora, se o array não sair do escopo do método é perfeitamente aceitável usá-lo em outros métodos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Não usar em prod.&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ReadMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Stream&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ArrayPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Rent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;memoryStream&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MemoryStream&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;SaveStreamIntoAFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memoryStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;ArrayPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Você certamente vai querer colocar isso no finally&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse caso, o &lt;code&gt;buffer&lt;/code&gt; foi passado para o método &lt;code&gt;SaveStreamIntoAFile&lt;/code&gt; e pode ser passado para outros métodos dentro, porém ele nunca vai sair do escopo do &lt;code&gt;ReadMessage&lt;/code&gt;, então é garantido que ele poderá ser retornado ao &lt;code&gt;ArrayPool&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusão
&lt;/h3&gt;

&lt;p&gt;A ideia desse artigo é mostrar que &lt;code&gt;ArrayPool&lt;/code&gt; não é pra ser usado em todo lugar e pode causar mais problemas do que resolver. A ideia não é desencorajar o uso dessa ferramenta, e sim trazer uma luz aos vários detalhes dessa API, que podem causar problemas no &lt;em&gt;software&lt;/em&gt; caso sejam ignorados. Em alguns pontos do seu código vai ser claro quando usar, e quando isso acontecer use. E quando não for claro, &lt;em&gt;profile&lt;/em&gt; seu código para ter certeza de que o uso do &lt;code&gt;ArrayPool&lt;/code&gt; vai trazer benefícios, mas na dúvida não utilize. Caso queira se aprofundar um pouco mais recomendo esse vídeo do # Stephen Toub sobre &lt;code&gt;ArrayPool&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/bw7ljmvbrr0" rel="noopener noreferrer"&gt;https://youtu.be/bw7ljmvbrr0&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;P.S.: Se você está preocupad@ com a possível pressão de memória gerada pelos arrays dentro do &lt;code&gt;ArrayPool&lt;/code&gt;, pode ficar &lt;a href="mailto:tranquil@"&gt;tranquil@&lt;/a&gt;. Existem algumas políticas de limpeza e uma delas é a pressão de memória, caso haja, o &lt;code&gt;ArrayPool&lt;/code&gt; vai remover alguns arrays para serem coletados pelo GC.&lt;/p&gt;

&lt;p&gt;Agradeço ao Rafael pela revisão.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>performance</category>
    </item>
    <item>
      <title>Alocações em .NET</title>
      <dc:creator>Pedro Jesus</dc:creator>
      <pubDate>Thu, 17 Jul 2025 18:11:20 +0000</pubDate>
      <link>https://dev.to/jesus/alocacoes-em-net-582f</link>
      <guid>https://dev.to/jesus/alocacoes-em-net-582f</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Reference Type é alocada na memória heap e Value Type é alocada na memória Stack.&lt;/p&gt;

&lt;p&gt;Já adianto que essa afirmativa, acima, está errada!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Se essa afirmativa acima, ou uma variante dela, te parece correta, esse artigo é pra você. Já cansei de ver inúmeros artigos brasileiros (acredito que todos os que vi) sobre gerenciamento de memória fazendo essa afirmativa e, consequentemente espalhando desinformação.&lt;/p&gt;

&lt;p&gt;Para &lt;code&gt;Reference Type&lt;/code&gt;, é &lt;em&gt;ok&lt;/em&gt; considerar que é armazenado na memória &lt;em&gt;heap&lt;/em&gt;, até porque é muito sutil quando não é. Agora, é bem comum &lt;code&gt;Value Types&lt;/code&gt; serem armazenados fora da memória &lt;em&gt;stack&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Ainda sobre a afirmativa acima. Isso já foi debatido, em 2018, pelo time que trabalha no &lt;em&gt;runtime&lt;/em&gt; e na linguagem, você pode ver toda a discussão &lt;a href="https://github.com/dotnet/docs/issues/4561" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;. Resultando na &lt;a href="https://github.com/dotnet/docs/pull/17120" rel="noopener noreferrer"&gt;atualização da documentação&lt;/a&gt; oficial para remover tal afirmativa.&lt;/p&gt;

&lt;p&gt;Ter esse conceito errado pode não atrapalhar sua carreira agora, principalmente se você for júnior ou até mesmo pleno, porém para os níveis sênior ou master/especialista já é problemático. Uma vez que haverá necessidade de escrever códigos performáticos ou até mesmo investigar/debugar um problema de perfomance. Ter esse modelo de memória equivocado vai te atrapalhar. Sem mais delongas...&lt;/p&gt;

&lt;h2&gt;
  
  
  Definição
&lt;/h2&gt;

&lt;p&gt;Vamos começar pela definição de cada um desses termos, pela &lt;a href="https://ecma-international.org/wp-content/uploads/ECMA-335_6th_edition_june_2012.pdf" rel="noopener noreferrer"&gt;ECMA-335&lt;/a&gt; pode-se dizer (livre tradução):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Value Type: Valores descritos por um tipo de valor são independentes (cada um pode ser compreendido sem referência a outros valores);&lt;/li&gt;
&lt;li&gt;Reference Type: Valores do tipo referência representam o endereço de um outro valor, que podem ser de 4 tipos, sendo eles objeto, interface, pointeiro e &lt;em&gt;built-in reference types&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Value Type
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Value Types&lt;/code&gt; em C# são os tipos representados por &lt;code&gt;struct&lt;/code&gt; e quando utilizadas em código são passadas por valor, ou seja, é feita uma cópia do &lt;code&gt;Value Type&lt;/code&gt; em questão.&lt;br&gt;
Um exemplo desse comportamento.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 42&lt;/span&gt;
&lt;span class="nf"&gt;MudarValor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 42&lt;/span&gt;


&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;MudarValor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;69&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claro que você pode mudar esse comportamento e passar o &lt;code&gt;Value Type&lt;/code&gt; por referência, através de um &lt;em&gt;manager pointer&lt;/em&gt;. Em C# isso é feito através das &lt;em&gt;keywords&lt;/em&gt; &lt;code&gt;ref&lt;/code&gt; e &lt;code&gt;in&lt;/code&gt;, onde o &lt;code&gt;in&lt;/code&gt; indica que o &lt;code&gt;Value Type&lt;/code&gt; será passado como um referência &lt;code&gt;readonly&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 42&lt;/span&gt;
&lt;span class="nf"&gt;MudarValor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 69&lt;/span&gt;

&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;MudarValor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;69&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Utizando o &lt;code&gt;ref&lt;/code&gt; mudou-se o valor de &lt;code&gt;x&lt;/code&gt;, pois passou-se uma referência o local de memória e sobrescreveu o valor que estava lá.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Existem algumas limitações para se passar um &lt;code&gt;Value Type&lt;/code&gt; por referência. Por exemplo, métodos assíncronos não podem ter parâmetros &lt;code&gt;in&lt;/code&gt; ou &lt;code&gt;ref&lt;/code&gt;. E essa limitação ocorre pelo simples fato de que, em métodos assíncronos, o &lt;code&gt;ValueType&lt;/code&gt; pode ir parar na memória &lt;em&gt;heap&lt;/em&gt;!&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;MudarValor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;MudarValor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;69&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Erro de compilação&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Por enquanto vamos ignorar o &lt;code&gt;ref struct&lt;/code&gt;, esse tipo terá um capítulo só para ele.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Reference Type
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Reference Type&lt;/code&gt; em C# são tipos que herdam de &lt;code&gt;System.Object&lt;/code&gt;  e &lt;strong&gt;não&lt;/strong&gt; herdam de &lt;code&gt;System.ValueType&lt;/code&gt;. Esse tipo guarda uma referência para um endereço de memória fazendo com as alterações sejam vista por todos que observam esse valor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;A&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;42&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 42&lt;/span&gt;
&lt;span class="nf"&gt;MudarValor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 69&lt;/span&gt;


&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;MudarValor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;69&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No exemplo acima, temos uma classe A e dentro dela um &lt;code&gt;field&lt;/code&gt; do tipo &lt;code&gt;int&lt;/code&gt; (&lt;code&gt;Value Type&lt;/code&gt;), e como você já deve ter "sacado", esse inteiro está na memória &lt;em&gt;heap&lt;/em&gt;. Ao passar &lt;code&gt;a&lt;/code&gt; para o método &lt;code&gt;MudarValor&lt;/code&gt; e alterar o valor &lt;code&gt;X&lt;/code&gt;, ele vai alterar o valor naquele espaço de memória, sobrescrevendo o valor que estava antes em &lt;code&gt;X&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Agora, quando se pensa nisso mais a fundo pode ocorrer algumas confusões, por exemplo neste caso.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;A&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;42&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 42&lt;/span&gt;
&lt;span class="nf"&gt;MudarValor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 42&lt;/span&gt;


&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;MudarValor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ficou confus@ pelo fato do segundo &lt;code&gt;WriteLine&lt;/code&gt; ter printado 42 em vez de uma &lt;code&gt;NullReferenceException&lt;/code&gt; ter estourado? Se não tiver ficado confus@ pode pular para o próximo capítulo, agora se ficou...&lt;/p&gt;

&lt;p&gt;Acontece que quando se passa &lt;code&gt;a&lt;/code&gt; para o método, esta se passando uma cópia de um ponteiro (ponteiros no C# funcionam como &lt;code&gt;Value Type&lt;/code&gt;), então eu estou anulado a copia dentro método, o ponteiro do método principal continua apontando para o endereço de memória onde &lt;code&gt;A&lt;/code&gt; está alocado e com isso não vai ter uma &lt;code&gt;NullReferenceException&lt;/code&gt;. Isso pode mudar se &lt;code&gt;a&lt;/code&gt; for passado por referência. Por exemplo...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;A&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;42&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 42&lt;/span&gt;
&lt;span class="nf"&gt;MudarValor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// NullReferenceException&lt;/span&gt;

&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;MudarValor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora temos a &lt;code&gt;NullReferenceException&lt;/code&gt;, e o motivo é que o método &lt;code&gt;MudarValor&lt;/code&gt; recebe uma referência de memória de onde está o ponteiro que referência &lt;code&gt;A&lt;/code&gt;, e ao marcar como &lt;code&gt;null&lt;/code&gt;, dentro do método, aquele espaço na memória será sobrescrito com &lt;code&gt;null&lt;/code&gt;, causando a &lt;code&gt;Exception&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Onde eles vivem?
&lt;/h2&gt;

&lt;p&gt;Eu espero, que até aqui tenha ficado claro que &lt;code&gt;Value Type&lt;/code&gt; pode viver tanto na memória &lt;em&gt;stack&lt;/em&gt; quanto na &lt;em&gt;heap&lt;/em&gt; e &lt;code&gt;Reference Type&lt;/code&gt; vive na memória &lt;em&gt;heap&lt;/em&gt;. Se estiver claro, vamos ir pouco mais fundo...&lt;/p&gt;

&lt;p&gt;O local onde esses tipos serão alocados vai depender do contexto em que estão sendo criados e de análises feitas pelo compilador. Se o compilador ver sentido um &lt;code&gt;Value Type&lt;/code&gt; pode ser alocado em um &lt;em&gt;CPU register&lt;/em&gt;, que é ainda mais rápido que a memória &lt;em&gt;stack&lt;/em&gt;, ou seja, em alguns casos o &lt;code&gt;Value Type&lt;/code&gt; nem vai viver na memória &lt;em&gt;stack&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;Quando ocorrer um &lt;em&gt;boxing&lt;/em&gt; o &lt;code&gt;Value Type&lt;/code&gt; é alocado na memória &lt;em&gt;heap&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Não está na heap&lt;/span&gt;
&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;boxing&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//Está na heap&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Mesmo quando ocorre o &lt;code&gt;boxing&lt;/code&gt; o comportamento de &lt;code&gt;Value Type&lt;/code&gt; se mantém, isto é, ele é passado como cópia quando for utilizado. Você pode ver isso &lt;a href="https://sharplab.io/#v2:C4LgTgrgdgPgAgJgAwFgBQiCM710wTgAoAiQHg3AQfeIEoBuHNASymAAIAPFgXhYBYE60AewBGAKwCmAY1bDBbJgHMu7AehETpLAF7LZ8qAtVod3HkiN4iexbSA=" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;E sobre &lt;code&gt;Reference Types&lt;/code&gt;, por padrão, estará alocado na memória &lt;em&gt;heap&lt;/em&gt;, mas eles também podem ser alocados na memória &lt;em&gt;Stack&lt;/em&gt; ou &lt;em&gt;CPU Registers&lt;/em&gt; se o compilador perceber que essa classe e seus membros estão limitados ao tempo de vida do método, isso ocorre por algo chamado &lt;code&gt;Escape analysis&lt;/code&gt; que você pode ler mais sobre &lt;a href="https://github.com/dotnet/runtime/blob/main/docs/design/coreclr/jit/object-stack-allocation.md" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como devo pensar então?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Reference Type é alocada na memória heap e Value Type é alocada na memória Stack.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Acredito que ao chegar aqui essa frase, também, te pareça errada. E deve ter ficado uma pergunta "Então, como devo pensar sobre isso?" e como disse &lt;a href="https://bsky.app/profile/ericlippert.com" rel="noopener noreferrer"&gt;Eric Lippert&lt;/a&gt; o melhor jeito a se pensar é &lt;em&gt;short term storage&lt;/em&gt; (armazenamento de curto tempo de vida, em tradução livre) e &lt;em&gt;long term storage&lt;/em&gt; (armazenamento de longo tempo de vida, em tradução livre). Então, se o &lt;code&gt;objeto&lt;/code&gt; (tanto &lt;code&gt;Value Type&lt;/code&gt; quanto &lt;code&gt;Reference Type&lt;/code&gt;) estiver alocado na &lt;em&gt;heap&lt;/em&gt; terá um tempo de vida longo. Se não, terá um tempo de vida curto. Pensar dessa forma torna mais assertiva a investigação de gerenciamento de memória no seu &lt;em&gt;software&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Vale lembrar, que uma &lt;code&gt;struct&lt;/code&gt; pode ser alocada inicialmente fora da &lt;em&gt;heap&lt;/em&gt; e promovida para &lt;em&gt;heap&lt;/em&gt; se tornando &lt;em&gt;long term storage&lt;/em&gt;. É muito fácil perceber isso na &lt;code&gt;AsyncStateMachine&lt;/code&gt;, que só irá ser alocada na &lt;em&gt;heap&lt;/em&gt; se o método marcado com &lt;code&gt;async&lt;/code&gt; completar-se de maneira assíncrona, ou seja, o &lt;em&gt;framework&lt;/em&gt; irá chamar o método&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;IAsyncStateMachine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetStateMachine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IAsyncStateMachine&lt;/span&gt; &lt;span class="n"&gt;stateMachine&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fazendo o &lt;em&gt;boxing&lt;/em&gt; da &lt;code&gt;struct&lt;/code&gt; e movendo-a para a memória &lt;em&gt;heap&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Se quiser olhar mais afundo sobre a relação de métodos marcados com &lt;code&gt;async&lt;/code&gt; e o &lt;code&gt;AsyncStateMachine&lt;/code&gt;, recomendo o &lt;a href="https://dev.to/angelobelchior/por-debaixo-do-capo-asyncawait-e-as-magicas-do-compilador-csharp-28ol"&gt;post&lt;/a&gt; do &lt;a href="https://dev.to/angelobelchior"&gt;Angelo&lt;/a&gt; sobre o tema.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Espero que você tenha aprendido, pelo menos, uma coisa nova sobre gerenciamento de memória no .NET e espalhe a palavra. É importante que mais artigos tragam as informações corretas e validadas pelo time que trabalha na linguagem.&lt;/p&gt;

&lt;p&gt;Este artigo foi bem simplificado e introdutório, e isso foi proposital, não quis adicionar muita informação aqui e sim dar uma base para que você aprenda o conceito de forma correta e consiga procurar mais referências sobre o tema, os links que deixei espalhado por este artigo são um bom começo.&lt;/p&gt;

&lt;h2&gt;
  
  
  ref struct (Bônus)
&lt;/h2&gt;

&lt;p&gt;Como prometido, um capítulo apenas para esse tipo especial de &lt;code&gt;Value Type&lt;/code&gt;, introduzido no C# 7.2 em 2017. A &lt;code&gt;ref struct&lt;/code&gt; é um &lt;code&gt;Value Type&lt;/code&gt; que &lt;strong&gt;NÃO&lt;/strong&gt; pode viver na &lt;em&gt;heap&lt;/em&gt;. Ela tem um tempo de vida curto e não pode escapar do contexto do método em que foi criada, com isso ela tem uma série de limitações, garantidas pelo compilador, mas no fim das contas é apenas uma &lt;code&gt;struct&lt;/code&gt;, como pode ser visto nesse &lt;a href="[SharpLab](https://sharplab.io/#v2:D4AQTAjAsAUCDMACATgUwGaIM4BdkFcBjHRAYUQG9ZEbEE6AWRAWQAoBKS62gX1j5ix6uAsUQAhRLCoxadJCCZtOFATyA===)"&gt;&lt;em&gt;lowering&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Esse tipo é utilizado, especialmente, em algoritmos de alta performance. A garantia de que ela não vai vazar para a &lt;em&gt;heap&lt;/em&gt;, e por isso não será gerenciada pelo &lt;em&gt;Garbage Collector&lt;/em&gt;, e por isso o endereço desses objetos são determinísticos, ou seja, uma vez alocado ele não mudará, logo não é necessário fazer verificações para ver se o objeto ainda está no mesmo endereço.&lt;/p&gt;

&lt;p&gt;Porém, não caia na armadilha de achar que &lt;code&gt;Value Type&lt;/code&gt; é sempre mais performático que &lt;code&gt;Reference Type&lt;/code&gt;. Antes de refatorar seu código, baseado em um post duvidoso do Linkedin (praticamente todos os posts sobre &lt;em&gt;benchmark&lt;/em&gt; ou gerenciamento de memória são duvidosos), faça medições para ter certeza que a mudança trará ganhos!&lt;/p&gt;

&lt;p&gt;Finalizo a parte bônus com essa imagem e recomendando a palestra ministrada pelo Andy no .NET Conf 2024, &lt;a href="https://youtu.be/1bsTnaLchi4?list=PLdo4fOcmZ0oXeSG8BgCVru3zQtw_K4ANY" rel="noopener noreferrer"&gt;New Features in the .NET 9 JIT&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>performance</category>
    </item>
    <item>
      <title>.NET: Brincando com ref structs</title>
      <dc:creator>Pedro Jesus</dc:creator>
      <pubDate>Wed, 03 Apr 2024 20:49:26 +0000</pubDate>
      <link>https://dev.to/jesus/net-brincando-com-ref-structs-1g4</link>
      <guid>https://dev.to/jesus/net-brincando-com-ref-structs-1g4</guid>
      <description>&lt;p&gt;Dias atrás, resolvi brincar com &lt;a href="https://learn.microsoft.com/pt-br/dotnet/csharp/language-reference/builtin-types/ref-struct" rel="noopener noreferrer"&gt;ref structs&lt;/a&gt;, fazendo alguns experimentos e pensando em como reduzir o &lt;a href="https://www.freecodecamp.org/portuguese/news/o-que-e-um-boilerplate-e-por-que-o-usamos-a-necessidade-de-um-guia-de-estilo-de-codigo/" rel="noopener noreferrer"&gt;&lt;em&gt;boilerplate&lt;/em&gt;&lt;/a&gt; de usar &lt;em&gt;try/finally&lt;/em&gt; para trocar o valor de uma variável Booleana. Foi um processo divertido. Como vejo pouco conteúdo sobre &lt;code&gt;ref structs&lt;/code&gt;, em pt-BR, resolvi compartilhá-lo aqui. Acredito que vai ficar um pouco grande, pois vou falar sobre vários aspectos que fiz e alguns problemas e soluções. Irei separar em subtítulos para facilitar a leitura.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O código apresentado aqui é bem simples. Caso queira usá-lo em produção, sugiro adicionar alguns testes unitários para garantir o perfeito funcionamento.&lt;br&gt;
E O MAIS IMPORTATE, conte-me como foi!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  1. O Problema
&lt;/h2&gt;

&lt;p&gt;Diversas vezes, me vi escrevendo códigos que precisam de um valor Booleano para saber se a lógica deve ser executada ou não. Usualmente, algo assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ViewModel&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SomeCode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Código omitido...&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;finally&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Imagine que teria de utilizar essa &lt;code&gt;flag&lt;/code&gt; em vários lugares, métodos dentro dessa classe ou até esse mesmo padrão em outros lugares... Não gostaria de ter que ficar reescrevendo essa estrutura do try/finally, pois ela é bem extensa. Quero uma solução que eliminará esse &lt;em&gt;boilerplate&lt;/em&gt; e garantirá que não impactará a performance da aplicação. Se você já está mais familiarizado com performance, sabe que o ideal é evitar que existam alocações na memória &lt;em&gt;heap&lt;/em&gt;. E para garantir isso vou precisar de usar &lt;code&gt;ref struct&lt;/code&gt; (não confundir com &lt;code&gt;struct&lt;/code&gt;).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Mesmo que &lt;code&gt;struct&lt;/code&gt; seja um &lt;code&gt;ValueType&lt;/code&gt;, isso não é garantia que ela estará na memória &lt;em&gt;stack&lt;/em&gt;. Com isso, aquela afirmação de que "ValueType vive na stack e ReferenceType vive na heap" é um equivoco enorme! &lt;br&gt;
Existem muito mais nuances, &lt;a href="https://github.com/dotnet/docs/issues/4561" rel="noopener noreferrer"&gt;eis aqui uma discussão&lt;/a&gt; do time que escreve a linguagem e o &lt;em&gt;runtime&lt;/em&gt; sobre esse tema, vale a pena a leitura.&lt;br&gt;
Apenas um exemplo: para provar meu ponto, uma &lt;code&gt;List&amp;lt;int&amp;gt;&lt;/code&gt; terá seus valores, que são inteiros (&lt;code&gt;ValueType&lt;/code&gt;s), alocados na memória &lt;em&gt;heap&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. Começando a solucionar o problema
&lt;/h2&gt;

&lt;p&gt;Então, como dito anteriormente, quero garantir que a solução viva na memória &lt;em&gt;stack&lt;/em&gt;, tendo o mínimo de impacto na performance da aplicação - tenhamos isso em mente. Antes de começar a implementar uma API, &lt;strong&gt;EU&lt;/strong&gt; gosto de pensar em como gostaria de consumir esse código. Com isso definido, fica mais fácil trabalhar na implementação. Claro que pode haver mudanças durante o processo por conta de alguma limitação. Então, abaixo está o código que eu desejo escrever:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ViewModel&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SomeCode_Jeito1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MyRefStruct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valueToSet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Resto da lógica&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SomeCode_Jeito2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MyRefStruct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valueToSet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Resto da lógica&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// Outra lógica&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Por padrão, todo &lt;code&gt;ValueType&lt;/code&gt; é passado como cópia. Para garantir que a mudança de valor dentro de &lt;code&gt;MyRefStruct&lt;/code&gt; seja propagada para o &lt;code&gt;flag&lt;/code&gt; dentro da classe &lt;code&gt;ViewModel&lt;/code&gt;, ele deve ser passado por referência.&lt;/li&gt;
&lt;li&gt;Eu quero "setar" o valor da &lt;code&gt;flag&lt;/code&gt; para &lt;code&gt;true&lt;/code&gt; quando for começar a lógica, por isso adiciono o segundo parâmetro no construtor.&lt;/li&gt;
&lt;li&gt;O &lt;code&gt;using&lt;/code&gt; garantirá que tudo entre &lt;code&gt;using var _ ...&lt;/code&gt; e o último &lt;code&gt;}&lt;/code&gt; do método &lt;code&gt;SomeCode_Jeito1&lt;/code&gt; ficará dentro de um &lt;code&gt;try/finally&lt;/code&gt; e chamará o método &lt;code&gt;Dispose&lt;/code&gt; dentro de &lt;code&gt;MyRefStruct&lt;/code&gt;. Como você deve ter imaginado, dentro do &lt;code&gt;Dispose&lt;/code&gt; mudaremos o valor de &lt;code&gt;flag&lt;/code&gt; para &lt;code&gt;false&lt;/code&gt;. No caso do método &lt;code&gt;SomeCode_Jeito2&lt;/code&gt;, tudo que estiver entre as &lt;code&gt;{}&lt;/code&gt; do &lt;code&gt;using&lt;/code&gt; ficará dentro de um &lt;code&gt;try/finally&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Aproveitando, adivinhe onde a variável &lt;code&gt;flag&lt;/code&gt; ficará &lt;a href="https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEUCuA7AHwAEAmARgFgAoagNwEMoACMJgXibxgHcmBhABQBKANzVxVIgGYmpfkwDe1JiqYAHKAEsGGGE2AQIAGyYAzI/QDm7M/SMBnGGKqqmy1e5XT+wz4r+uDMwINqZ2js6urqQArBgAFpr2on4Avn4ZVOk0VEA=" rel="noopener noreferrer"&gt;alocada&lt;/a&gt;? &lt;strong&gt;Não&lt;/strong&gt; é na memória &lt;em&gt;stack&lt;/em&gt; 😉. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Essa abordagem me deixa bem contente. Afinal, troquei todo aquele &lt;em&gt;boilerplate&lt;/em&gt; por apenas 1 linha. Com esses itens em mente, criaremos nossa &lt;code&gt;ref struct&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Criando a ref struct
&lt;/h2&gt;

&lt;p&gt;Você já deve saber que para usar o &lt;code&gt;using&lt;/code&gt; eu preciso de implementar a interface &lt;a href="https://learn.microsoft.com/pt-br/dotnet/api/system.idisposable.dispose?view=net-8.0" rel="noopener noreferrer"&gt;&lt;code&gt;IDisposable&lt;/code&gt;&lt;/a&gt;. É uma interface bem simples, que tem apenas um método na sua definição &lt;code&gt;void Dispose()&lt;/code&gt;. Então, teríamos algo desse tipo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;HoldAndChangeValue&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IDisposable&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mas, isso não compilará! Por quê?! Bom, quando uma &lt;code&gt;struct&lt;/code&gt; implementa uma interface, ela pode ser alocada na memória &lt;em&gt;heap&lt;/em&gt;, por meio do &lt;a href="https://learn.microsoft.com/pt-br/dotnet/csharp/programming-guide/types/boxing-and-unboxing" rel="noopener noreferrer"&gt;&lt;em&gt;boxing&lt;/em&gt;&lt;/a&gt;. E como &lt;code&gt;ref struct&lt;/code&gt;s &lt;strong&gt;NÃO&lt;/strong&gt; podem ser alocadas na &lt;em&gt;heap&lt;/em&gt;, de jeito nenhum, o compilador não permite que ela implemente interfaces.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sim, meu jovem &lt;em&gt;Padawan&lt;/em&gt;, eu sabia dessa limitação, mas quis pregar uma peça em você. Consegui? Bom, se sim, agora, vou te ensinar algo bem bacana.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;"Para nossa alegria", várias funcionalidades da linguagem C# são baseadas em &lt;a href="https://pt.wikipedia.org/wiki/Duck_typing" rel="noopener noreferrer"&gt;&lt;em&gt;duck type&lt;/em&gt;&lt;/a&gt;. Logo, eu só preciso ter o método &lt;code&gt;public void Dispose(){}&lt;/code&gt; definido no meu tipo e, &lt;em&gt;voilà&lt;/em&gt;, podemos usá-lo. Para os outros tipos (&lt;code&gt;class&lt;/code&gt;, &lt;code&gt;struct&lt;/code&gt; etc), é necessário implementar a interface &lt;code&gt;IDisposable&lt;/code&gt;.&lt;br&gt;
Algumas funcionalidades do C# utilizam o &lt;em&gt;duck type&lt;/em&gt; , como: &lt;code&gt;foreach, async/await etc&lt;/code&gt;. Inclusive, &lt;a href="https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEUCuA7AHwAEAmABgFgAoUgRmqLIAIjaA6AJXwwEsBbGGwDCEPgAceAGxhQAyjIBuPMDADOAbgbNWAVk1UGtAJwAKAESAeDcAg+2YCU+w6YAiAQwwwAKv0EA5CAHc2AFkpSR5VGEg8ABN7BiMmFBJ9Vmc3T282P0CQyTCIqNiHAxpaJBYSFiQAUQRqAG9qJmamAHpWpgB5JgADIiMepjUxGRcoJhw+XqIkAEF/Fx53KEGYPAwAY4gmCKZt3jFtqIiAcxwYJjEoCAUZCammlvbpuYWlmVXpS4hoi4jxsz9FzAaRmNiPZpEADMLDKVXmi2WTAA4jAMAj3lATBgABbhJg8dZMBQuSTnWwQpiNKgtWksADsVTYThgkhcAE8TCSyTBbGxUei3ssTHEaS0AL7UcVAA=" rel="noopener noreferrer"&gt;eis aqui&lt;/a&gt; um exemplo de como fazer com que isto: &lt;code&gt;await 42;&lt;/code&gt;,  seja válido.&lt;/p&gt;

&lt;p&gt;Baseado nas informações dos parágrafos anteriores e em como queremos usar em código, nossa &lt;code&gt;HoldAndChangeValue&lt;/code&gt; ficará:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;HoldAndChangeValue&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;HoldAndChangeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;valueToSet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valueToSet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E é isso! O código fica mais simples de escrever e o funcionamento é como esperado. Fique a vontade para verificar &lt;a href="https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEUCuA7AHwAEAmABgFgAoUgRmqLIAIjakmXaA6AYQjwDOEADYwA3NUlUAbgEMoTaQFsmAXiZ4YAdyYA1AJbaAshAAmMYQAoAlBJlKuAZQhKYfczbvUA6lH0YYABl9TU8fPwDg0NspAHpYpkcYJghFWWFoJnMmADNhWQBzXMyMXBg0DQBj1Ll9JgAHPzwMeQ1ZU1kGiH0BNLrYDGg8eWp4pgyC1LxUyFcAc9TTVNdBpeplJxc3MxgwqgYSPUMtE3NhagBvagBIRv05AKZgCBFc/IKvKmuiAGYWFESW3cu2sNyuX2u+hyTEseUKoIh3wA7HYOGi0Tdrr5/EEQrsACQAIm4TAA8mkMgpsnCigBLpggJgXGkAX0JMQhjDSCgA+moNNomAAJESmACCeFMPAAFrI8AUYLp0jhdrBoTSKnJhCqACoQJJYJilFUc9Ho7GRPGWIkkLhkimZanvJj0xnM95sjnXa5jABKMAEgyynWEAGeCvowLIbizqLH9lQ1UxA7gwBhhaKJVLZfLFcqYJdqOik89XlqVZ90UW0b8M8JxZKZXKFUrtaqYNDS8I3oUKl2Kbr9TAMAj0eCzWjy8l1EmaaiJwPp4u9Qb5xx41WqOja0QAQARHr1CACEHVjjjhdT/kAQinlYXFtxoSJ5K1juSNJdDKZU5ZTDgTB7jAzRQIsqQAOQivWWZNrmrYquB7Jrkw8YskAA==" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No link acima, tente implementar a estrutura do método &lt;code&gt;SomeCode_Jeito2&lt;/code&gt;. Você perceberá que dentro das chaves o valor da &lt;code&gt;flag&lt;/code&gt; será &lt;code&gt;True&lt;/code&gt; e fora voltará para &lt;code&gt;False&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Acredito que vale a pena reforçar, que a &lt;code&gt;ref struct&lt;/code&gt; possui diversas limitações de uso. Isso serve para garantir que ela não seja alocada na memória &lt;em&gt;heap&lt;/em&gt;. Então, essa solução não funcionará em métodos que têm o modificador &lt;code&gt;async&lt;/code&gt;, dentro de uma &lt;em&gt;lambda expression&lt;/em&gt; que capture essa &lt;code&gt;ref struct&lt;/code&gt; em uma &lt;code&gt;closure&lt;/code&gt;, dentre outros cenários.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  4. Expandindo nossa ref struct
&lt;/h2&gt;

&lt;p&gt;A solução proposta no capítulo anterior resolve boa parte dos cenários. Porém, não lida com propriedades. Para quem usa o padrão MVVM, por exemplo, seria muito interessante ter suporte a propriedades. Acredito que já tenha visto a estrutura do &lt;code&gt;IsBusy&lt;/code&gt;. Caso não conheça, é semelhante ao exemplo que usei. Contudo, em vez de usar um &lt;code&gt;field&lt;/code&gt; utiliza-se uma propriedade.&lt;br&gt;
O maior problema é que não se pode passar propriedades como referência. Isso se deve ao fato de que propriedades, no C#, são um &lt;a href="https://pt.wikipedia.org/wiki/A%C3%A7%C3%BAcar_sint%C3%A1tico" rel="noopener noreferrer"&gt;&lt;em&gt;sugar syntax&lt;/em&gt;&lt;/a&gt; para métodos (&lt;em&gt;getter &amp;amp; setter&lt;/em&gt;).&lt;br&gt;
É possível ver isso &lt;a href="https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEBLANgHwAEAmARgFgAoQgZgAIS6BhOgbyqrq7oAcpsAbgEMMMOsAgRcdbAGcAQgFdZATwDcnbrXGTpASQXKVdTV3aVulugHMYGOgF4AfDMOqNFq11l3HLuUqqjnTCuIowHpYAvlRRQA=" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;. Dentro do &lt;a href="https://en.wikipedia.org/wiki/Common_Intermediate_Language" rel="noopener noreferrer"&gt;IL (&lt;em&gt;Intermediated Language&lt;/em&gt;)&lt;/a&gt;, você verá que não há um &lt;em&gt;valor&lt;/em&gt; para essa propriedade, como há para o &lt;em&gt;field&lt;/em&gt;, mas métodos de &lt;em&gt;get &amp;amp; set&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;E qual a solução? Pelo que pesquisei e experimentei, isso só pode ser feito usando &lt;a href="[Delegados%20%E2%80%93%20Guia%20de%20Programa%C3%A7%C3%A3o%20em%20C#%20|%20Microsoft%20Learn](https://learn.microsoft.com/pt-br/dotnet/csharp/programming-guide/delegates/)"&gt;&lt;code&gt;delegates&lt;/code&gt;&lt;/a&gt;. Nesse caso, usei uma &lt;a href="https://learn.microsoft.com/pt-br/dotnet/api/system.action-1?view=net-8.0" rel="noopener noreferrer"&gt;&lt;code&gt;Action&lt;/code&gt;&lt;/a&gt;. Só que &lt;code&gt;Action&lt;/code&gt;, assim como &lt;code&gt;delegates&lt;/code&gt;, são &lt;code&gt;ReferenceTypes&lt;/code&gt;. Logo, são alocados por padrão, na memória &lt;em&gt;heap&lt;/em&gt;... E agora?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Inclusive, se você souber outra maneira de copiar o comportamento do &lt;code&gt;ref&lt;/code&gt; com propriedades, conte-me, estou muito interessado!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Agora, é só adicionar uma &lt;code&gt;Action&lt;/code&gt; como parâmetro no construtor da &lt;code&gt;ref struct&lt;/code&gt; e criar uma variável local para isso e vida que segue... Mas, espere aí... Como colocarei algo que é alocado na &lt;em&gt;heap&lt;/em&gt; dentro de algo que não pode ser? Bom, se você conseguiu ler e entender a discussão que fiz referência no começo do artigo, sobre onde se alocam &lt;code&gt;ValueType &amp;amp; ReferenceType&lt;/code&gt;, ficará mais claro.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Digo "conseguiu ler e entender", acima, pois toda a discussão está em inglês e eu sei que nem todo mundo tem proficiência nessa linguagem, em um país como o nosso é completamente aceitável esse cenário. Particularmente, &lt;strong&gt;EU&lt;/strong&gt; digo que é muito importante praticar o inglês se quiser se tornar um(a) profissional melhor. De todo modo, acredito que as ferramentas que traduzem sites estejam bem melhores atualmente. Usem-nas sempre que possível. Mas, logo abaixo, eu explico melhor o "Eureka" desse caso em particular.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Continuando... Sim, nossa &lt;code&gt;ref struct&lt;/code&gt; &lt;strong&gt;NÃO&lt;/strong&gt; viverá na memória &lt;em&gt;heap&lt;/em&gt;, mas ela pode referenciar objetos que viverão. Isso porque o tempo de vida desses objetos serão maiores do que o tempo de vida de nossa &lt;code&gt;ref struct&lt;/code&gt;. Quando passarmos a &lt;code&gt;Action&lt;/code&gt; para nossa &lt;code&gt;ref struct&lt;/code&gt;, o que passaremos, na verdade, é o endereço de memória dessa &lt;code&gt;Action&lt;/code&gt;, o qual fica na memória &lt;em&gt;stack&lt;/em&gt;. Logo, ele pode viver tranquilamente na nossa &lt;code&gt;ref struct&lt;/code&gt;. Para uma visualização gráfica do que estou falando, acesse &lt;a href="https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEUCuA7AHwAEAmARgFgAoaosgTgAoBKAbmtpIAYOqB6AFQACagDkIQyAFsYeDAEOoASwkBDMEqmqhMBEoDOGGFKFSAlxggATCPqEAHVVG1K8++zA0Q8ToQCIIYAArGEt9P2pYaVkbIWBlPDBfaR19fRg7c0sbO0dnISMoIRwtITwIAHOAY4krGEkIKQkkq1VqGSl4iTMhaABzVTwlAC9VWJ9TYwBn5VU0IQN9CQA3VSUC+tV4pSKAWQBVAEkAFQB5IW0ZORgAQmoBPl48GAB3IQA1JVfd6xgAGxYADoAEJ/GAsdg0KikD5fF4/Op/agAb2oQnRQiIAGY4hAIH8hAAxP6qPpCZF9UKsdIYVgAXzRGOAeIJADMSWSALxCVmqP7pSEYkRUIXYzEoISg8HMRno1EioUYohcISrIrAVQYTXabnPN4ACXxVgAgngrABhAAWg0p7z5OHB7NJ8wwuBg8xYQk5AD4iRyvUIbsTSWxeIqMYc3B4wBhAQBlLVgADWjA1Wq1oYV4dIAFY09rM7KhAyqCXqIZcDGhIa/iazVabTA7X8HUIQEJDgARAz2WxbMEoovM/Gq+0wQVKsgkBxQCD2OgkCfootimt1i3WvC2seplk8jnzYcE1YtmDHCBx0LzBcXGMqPAyrPkotCk+t7lOvpLxVv+rc3/npetIvhi9izvOU4BuoGD3t+JZCiuOJEBK3buLY0pFvK4bor+AY3L+35CmBc4LhCRYlnSQA===" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Com isso, veremos, primeiramente, como eu gostaria de consumir o código e, então, implementaremos a solução.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ViewModel&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;IsBusy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IsBusy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;IsBusy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HoldAndChangeValueProperty&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;IsBusy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;IsBusy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Código a ser executado   &lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Deixo para você remover a linha &lt;code&gt;IsBusy = true;&lt;/code&gt; e a abstrair dentro da &lt;code&gt;ref struct&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A implementação, nesse caso, será bem simples também. Basta apenas passar a &lt;code&gt;Action&lt;/code&gt; para a &lt;code&gt;ref struct&lt;/code&gt; e a executar dentro do método &lt;code&gt;Dispose&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;HoldAndChangeValueProperty&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Action&lt;/span&gt; &lt;span class="n"&gt;propAction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;HoldAndChangeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;propAction&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;propAction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para ver o código em execução, basta acessar &lt;a href="https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEUCuA7AHwAEAmARgFgAoIgBgAIiylGyA6AYQjwGcIAbGAG5q1JgE4AFAEoRVMSVqiqAegBU9agDkI9SAFsYeDAEOoAS10BDMOf1X6MBOZ4YY++voCXGCABMIHnoABysoB3NeYJhbbjD6ACIIYAArGF8eBOpYAyMA+mALPDB4g0ceHhgg718AoNDw+jcoehx7ejwIAHOAY90/GD0IfV0SvytqQ31C3S96aABzKzxzAC8rfLwHKYBniys0ehc+egA3K3MmwatC8xaAWQBVAEkAFQB5em2jNwBCajUKmU5xapw8AF4OjAAO70ABq5hh938MH4MjkYLYACV8OjqAB1CxuAAykRgeKohPMJLJFMxOLwFIU8MR0ORA341AA3tR6HzGABmAoQAT0Z48ABCOB4AE96FyFukhJUMEIAL68/mavlEIVEFD0BkybXyk38+hUml4ckAEgS4qlssOyzcQWAVgwHoO9DmIHlDulMrVCVkZq1VHN5vMADN6JIA7LpGHI4wAOxyFN85NiyWB+iQjC4YTZ7N0M7xd2ez35qGwgASAj8AEE8H4OAALZaKuFWfg4GAABSgEGiUAwMskMnzAD4c465ZDfgmZaGI5nLTBSdbJHbl4cBsEIC4Cl7PYdff7c7Lg6vzRq11mH5on7rGAahxBzsanzyn+aN1utr2leMrOsYVQnlW3oXlyy43hmmbZjGcbLkmf6ZkQ6YluhfLLjWhb9ghKbZiCkFejW1r1o2LZtp2eDdr2/YfqO46TtIM5znmi6oURkYAbSu4gfuMCHseAxkWePr0H6sEgfB2GZvQKgqPQHZWPYra6LoAAiLiHpUnjLDgvaGOBhwGbkxjxFUPAOPwkSdtmynzJ4Pj+LoPA7PQlRQCYjgIDEOCegEhwGMEgieqZbiHGQZwwKsbDZpWXpsLpPD6eSt7rkSm4CcB87CaJbqnlYqV6YEmXntJl7zvJT73ve2QwLGri4GAGD0A2/DNq2an0TAPZ9oOw4sTK3ImkwJAhCNk28RNQpdT1tFdgNjHDSOMBjhOk1fO1lh4Gh5q/opwQzWQU2QjYGD7bx97mvNb70GlGXfkd2anSOk0Une1BqkAA" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Para dar suporte ao uso de propriedades, a solução, como um todo, tocará na memória &lt;em&gt;heap&lt;/em&gt;, pois precisaremos de uma &lt;code&gt;Action&lt;/code&gt; para fazê-lo funcionar corretamente. Alocando uma única &lt;code&gt;Action&lt;/code&gt; é algo tranquilo, pois o tamanho será de apenas alguns &lt;code&gt;bytes&lt;/code&gt;. O problema é se isso for um trecho de código muito executado, daí pode ser necessário verificar o impacto de performance. E é exatamente isso que vou falar no próximo capítulo.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Alocações implícitas (&lt;em&gt;Implicit Allocations&lt;/em&gt;)
&lt;/h2&gt;

&lt;p&gt;Basicamente, alocações implícitas são quando algo vai ser armazenado na memória &lt;em&gt;heap&lt;/em&gt;, mas sem que isso seja mostrado diretamente. Por exemplo, &lt;code&gt;var obj = new object();&lt;/code&gt;, essa chamada está alocando um novo &lt;code&gt;objeto&lt;/code&gt; na memória &lt;em&gt;heap&lt;/em&gt;. Isso é &lt;strong&gt;explicito&lt;/strong&gt;, pois estamos instanciando esse objeto com o uso da &lt;em&gt;keyword&lt;/em&gt; &lt;code&gt;new&lt;/code&gt;.&lt;br&gt;
Agora, &lt;code&gt;object i = 10;&lt;/code&gt; é uma alocação &lt;strong&gt;implícita&lt;/strong&gt;, por meio de &lt;em&gt;boxing&lt;/em&gt;. Estou convertendo o inteiro 10 em um &lt;code&gt;ReferenceType&lt;/code&gt;, que será armazenado na memória &lt;em&gt;heap&lt;/em&gt;. Se quiser aprofundar no tema, recomendo &lt;a href="https://devblogs.microsoft.com/pfxteam/know-thine-implicit-allocations/" rel="noopener noreferrer"&gt;este artigo&lt;/a&gt; do Stephen Toub.&lt;/p&gt;

&lt;p&gt;No nosso caso, onde acontece essa alocação? Ela ocorre quando passamos a &lt;code&gt;Action&lt;/code&gt; para a &lt;code&gt;ref struct&lt;/code&gt;. Se observamos o que o compilador gera pelo &lt;a href="https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA+ABATARgLABQGADAAQY5Lk4B0AwhAHYDOEANjANyGEUCcACgCU3AryzEeBAPQAqUoQByEUpAC2MRgBcAh1ACWKgIZh9ao6RgJ9zLTDWk1AS60QAJhGakADkagX9Fm8YUyY/UgAiCGAAKxhXZgjCWHVND1JgA0YwcPVLZmYYL2dXDy9ff1I7KFIAV3NSRggAc4BjlTcYVQg1FRy3I0INNUyVJ1JoAHMjRn0ALyN0xgthgGeDIwAaUhtWUgA3I30qrqNM/RqAWQBVAEkAFQB5UhXNOwBCQllpKUOa/YcAF5GjAAO6kABq+jBl3cMDYwlEAJoACVaoxEYQAOoGOwAGUCMExBBx+nxhOJyLRGJEUmwkOhoNhnTYhAA3oRSFzyABmDIQdikW7MABCtWYAE9SGzJvFOIUtJwAL6c7mqrkYPkYFCkanCdXSg0KAjc03Gs3c/QAM1IAmFYslQiNFvIAHZRC7zS77eKpcCtFBalxnVyQ+QyH8MkYtNGLMDGGDSAAJdhuACCjDcdAAFjNZRCjGwgwAFKAQYJQLQSgTCUiAgB8QtFvrrpHePsdHtNBpVBF7yRgNtsgbAWmTqYzWdzjHzhZLZYrVfZBooWB8C9XXdDJu5mvHbHTmZzeZgBaLMFL5Zglerq5eo8MjCdO65HJfZu8G5wa+BJi0j63Uhe27d8921UgABEbG8TwiWfU0309T9y1XYlTV7JUgA==" rel="noopener noreferrer"&gt;código&lt;/a&gt;, você verá que o compilador reescreve boa parte do nosso código, mas a principal, nesse cenário, é esta linha:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// O que escrevemos&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HoldAndChangeValueProperty&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;IsBusy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;IsBusy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Será reescrita em:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Como o compilador reescreve&lt;/span&gt;
&lt;span class="n"&gt;HoldAndChangeValueProperty&lt;/span&gt; &lt;span class="n"&gt;holdAndChangeValueProperty&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HoldAndChangeValueProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;b__4_0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Onde o &lt;code&gt;&amp;lt;Run&amp;gt;b__4_0&lt;/code&gt; é um método gerado pelo compilador. Olhando essa linha, é possível perceber que toda vez que esse método é executado, será alocada uma nova &lt;code&gt;Action&lt;/code&gt;, que executará o mesmo método... Isso é bem ineficiente, afinal se o método é o mesmo por que não fazer um &lt;em&gt;cache&lt;/em&gt;?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Você já deve ter ouvido/lido a seguinte frase "compiladores são burros". Se não ouviu, acredito que ouvirá/lerá em algum momento da jornada como pessoa desenvolvedora. Eu concordei com essa frase por muito tempo. Agora, eu penso de outra maneira. Eu diria que os compiladores são conservadores, eles preferem, por padrão, garantir o funcionamento correto em vez de otimizações.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Como, por padrão, compiladores preferem garantir estabilidade em vez de otimizações. Esse tipo de cenário é bem comum em vários pontos de qualquer linguagem.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 Entendendo e solucionado o problema
&lt;/h3&gt;

&lt;p&gt;Vamos criar um cenário em que esse trecho de código será executado 10 mil vezes. O que você acha que ocorrerá? Exato, serão alocadas 10 mil &lt;code&gt;Action&lt;/code&gt;s para fazer exatamente a mesma coisa. Para comprovar, criei um código de teste. O método que será utilizado para analisar as alocações é este:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;10_000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="m"&gt;5_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadLine&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao final da execução, eis os resultados:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fobq3it11tdd0n8deftec.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fobq3it11tdd0n8deftec.png" alt="Imagem do resultado de alocações de System.Action na classe ViewModel." width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como podemos ver a classe &lt;code&gt;ViewModel&lt;/code&gt; no método &lt;code&gt;Run&lt;/code&gt;, alocou 10 mil &lt;code&gt;Actions&lt;/code&gt;, como eu havia dito. Para mim, esse comportamento é inaceitável. Mas, ele é um problema que está fora do escopo da nossa &lt;code&gt;ref struct&lt;/code&gt;, pois quem cria essas alocações é o compilador. Para resolver isso, devemos criar, manualmente, o &lt;em&gt;cache&lt;/em&gt; dessa &lt;code&gt;Action&lt;/code&gt; e usá-la. &lt;em&gt;Refatorando&lt;/em&gt; o código da &lt;code&gt;ViewModel&lt;/code&gt;, teremos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ViewModel&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;IsBusy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt; &lt;span class="n"&gt;updateIsBusy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;updateIsBusy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;IsBusy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;IsBusy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HoldAndChangeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;updateIsBusy&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Código a ser executado&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com essa mudança, o código gerado pelo compilador será:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HoldAndChangeValueProperty&lt;/span&gt; &lt;span class="n"&gt;holdAndChangeValueProperty&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HoldAndChangeValueProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;updateIsBusy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como podemos ver, não existe mais uma nova alocação toda vez que o método &lt;code&gt;Run&lt;/code&gt; rodar. Para comprovar, utilizaremos o mesmo código de testes nessa nova versão da classe &lt;code&gt;ViewModel&lt;/code&gt;. Os resultados podem ser vistos na imagem abaixo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl7axk32gaf0yilzd6n13.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl7axk32gaf0yilzd6n13.png" alt="Imagem do resultado de alocações de System.Action na classe ViewModel." width="800" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como pode ser observado, apenas uma &lt;code&gt;Action&lt;/code&gt; foi instanciada e será utilizada em todas as chamadas do método &lt;code&gt;ViewModel.Run&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  6. Conclusão
&lt;/h2&gt;

&lt;p&gt;Concluímos nossa aventura pela &lt;code&gt;ref struct&lt;/code&gt;. Como você deve ter notado, existe bastante coisa para se entender além da &lt;code&gt;ref struct&lt;/code&gt; por si só. Espero que as referências, aqui citadas, possam te ajudar nessa jornada e agregar ainda mais conhecimento.&lt;/p&gt;

&lt;p&gt;Não tenha medo de utilizar &lt;code&gt;ref struct&lt;/code&gt;s. É um recurso novo na linguagem, bem nichado também, mas vale a pena se familiarizar com ele e outros recursos. Afinal, eles permitem que possamos escrever códigos performáticos sem precisar de usar &lt;code&gt;unsafe&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Por favor, conte-me suas aventuras com &lt;code&gt;ref struct&lt;/code&gt;. Estou muito interessado no que você criará!&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>struct</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
