Should avoid boxing of value types when using string interpolation in a StringBuilder
#116731
-
I came across of the boxing behavior of Small snippet to reproduce the boxing behavior of public static void Test_StringBuilder_string_interpolation()
{
var sb = new StringBuilder(50);
var start = GC.GetAllocatedBytesForCurrentThread();
sb.Append($"float:{1.4f}");
// boxing is caused by the cast to ISpanFormattable
// if (((ISpanFormattable)value).TryFormat(...)
var diff = GC.GetAllocatedBytesForCurrentThread() - start;
Assert.AreEqual(0, diff); // diff == 24
} The line that boxes is at: |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 3 replies
-
To avoid boxing the approach described below could be used. The method called by string interpolation is: So the method uses an unconstraint generic type. So the call of SpanFormat<T>.TryFormat(value, destination, out int charsWritten, default, _provider); Here the small snippet which creates the delegate. internal delegate bool SpanFormattableTryFormat<in T>(T value, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider);
internal static class SpanFormat<T>
{
internal static readonly SpanFormattableTryFormat<T> TryFormat = (SpanFormattableTryFormat<T>)SpanFormat.CreateTryFormat(typeof(T), typeof(SpanFormattableTryFormat<T>));
}
internal static class SpanFormat
{
internal static Delegate CreateTryFormat(Type type, Type delegateType)
{
var methodInfo = typeof(SpanFormat).GetMethod("TryFormat", BindingFlags.Static | BindingFlags.NonPublic)!;
var genericMethod = methodInfo.MakeGenericMethod(type);
return Delegate.CreateDelegate(delegateType, genericMethod);
}
internal static bool TryFormat<TSpanFormattable> (TSpanFormattable value, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
where TSpanFormattable : ISpanFormattable
{
return value.TryFormat(destination, out charsWritten, format, provider);
}
} |
Beta Was this translation helpful? Give feedback.
-
That boxing doesn't happen in optimized tier 1 as it gets optimized out. If you're seeing allocation from that, you're likely looking at umoptimized and/or tier 0. |
Beta Was this translation helpful? Give feedback.
That boxing doesn't happen in optimized tier 1 as it gets optimized out. If you're seeing allocation from that, you're likely looking at umoptimized and/or tier 0.