mirror of
https://github.com/icsharpcode/ILSpy.git
synced 2026-10-12 02:15:58 +00:00
Roslyn caches a ReadOnlySpan<T> created from an array literal in a
<PrivateImplementationDetails> field on target frameworks without
RuntimeHelpers.CreateSpan (e.g. .NET Framework / netstandard2.0 + System.Memory):
object obj = <PrivateImplementationDetails>.cache;
if (obj == null) {
obj = new char[] { '\r', '\n' };
<PrivateImplementationDetails>.cache = (char[])obj;
}
... new ReadOnlySpan<char>((char[])obj) ...
The decompiled output referenced the compiler-synthesized
<PrivateImplementationDetails> type, whose escaped name is not expressible in C#
and is never declared, so the output failed to recompile (CS0400).
The modern RuntimeHelpers.CreateSpan form was already handled
(TransformRuntimeHelpersCreateSpanInitialization); this adds the analogous
handling for the legacy lazy-cache form, mirroring CachedDelegateInitialization
(which collapses the same lazy-static-field cache for anonymous-method delegates).
Once the cache is collapsed, the existing array-initializer transforms recover
the array literal, so the <PrivateImplementationDetails> reference disappears.
Test: ILPretty/CachedReadOnlySpanInitialization.
18 lines
681 B
C#
18 lines
681 B
C#
using System;
|
|
|
|
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
|
{
|
|
public static class CachedReadOnlySpanInitialization
|
|
{
|
|
// On target frameworks without RuntimeHelpers.CreateSpan (before .NET 7) Roslyn emits a
|
|
// compiler-generated lazy cache in <PrivateImplementationDetails> for a ReadOnlySpan<char>
|
|
// created from a multi-byte array literal. The CachedReadOnlySpanInitialization transform
|
|
// collapses that cache back to the explicit ReadOnlySpan constructor.
|
|
#if NET70
|
|
public static ReadOnlySpan<char> NewLine => new char[2] { '\r', '\n' };
|
|
#else
|
|
public static ReadOnlySpan<char> NewLine => new ReadOnlySpan<char>(new char[2] { '\r', '\n' });
|
|
#endif
|
|
}
|
|
}
|