Sobrecargas de StringBuilder.Append y orden de evaluación

En C# 10 se agrega compatibilidad para una mejor interpolación de cadenas, incluida la capacidad de seleccionar como destino "controladores" personalizados además de cadenas. StringBuilder aprovecha esta ventaja con nuevas sobrecargas de Append y AppendLine que aceptan un controlador de cadenas interpoladas personalizado. Ahora es posible que las llamadas existentes a estos métodos inicien el enlace a las nuevas sobrecargas. En general, el comportamiento es idéntico, pero con un rendimiento mejorado. Por ejemplo, en lugar de crear primero una cadena y luego anexarla, los componentes individuales de la cadena interpolada se anexan directamente al generador. Pero esto puede cambiar el orden de evaluación de los objetos usados como elementos de formato, lo que puede manifestarse como una diferencia de comportamiento.

Comportamiento anterior

En versiones anteriores, una llamada a:

stringBuilder.Append($"{a} {b}");

se compilaba en el equivalente de:

stringBuilder.Append(string.Format("{0} {1}", a, b));

Esto significa que se evalúa a, después se evalúa b, luego se crea una cadena a partir de los resultados de esas evaluaciones y, después, esa cadena se anexa al generador.

Comportamiento nuevo

A partir de .NET 6, una llamada a:

stringBuilder.Append($"{a} {b}");

se compila en el equivalente de:

var handler = new StringBuilder.AppendInterpolatedStringHandler(1, 2, stringBuilder);
handler.AppendFormatted(a);
handler.AppendLiteral(" ");
handler.AppendFormatted(b);
stringBuilder.Append(ref handler);

Esto significa que a se evalúa y anexa al generador y, después, se evalúa b y se anexa al generador.

Si, por ejemplo, a o b es el propio generador, como se muestra en el código siguiente, el nuevo orden de evaluación puede dar lugar a otro comportamiento en tiempo de ejecución.

stringBuilder.Append($"{a} {stringBuilder}");

Versión introducida

6.0 RC 1

Tipo de cambio importante

Este cambio puede afectar a la compatibilidad de orígenes.

Motivo del cambio

Es habitual que los desarrolladores pasen cadenas interpoladas a StringBuilder, ya que es más cómodo que dividir manualmente la cadena y llamar a StringBuilder.Append para cada elemento. Estas nuevas sobrecargas permiten la sintaxis concisa y la mayor parte del rendimiento de realizar las llamadas individuales.

En la mayoría de los casos en los que se usan StringBuilder.Append y StringBuilder.AppendLine no observará una diferencia funcional. Si encuentra una diferencia que resulta problemática, puede restaurar el comportamiento anterior si agrega una conversión a (string) antes de la cadena interpolada. Por ejemplo:

stringBuilder.Append((string)$"{a} {b}")

Pero no se recomienda, a menos que realmente sea necesario para la compatibilidad.

API afectadas

Vea también