Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/IO/TextWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Buffers;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.CompilerServices;
Expand All @@ -25,6 +26,9 @@ public abstract partial class TextWriter : MarshalByRefObject, IDisposable, IAsy
// We don't want to allocate on every TextWriter creation, so cache the char array.
private static readonly char[] s_coreNewLine = Environment.NewLineConst.ToCharArray();

// s_coreNewLine will be ['\r', '\n'] on Windows and ['\n'] on Unix. This is the opposite, lazily created/cached.
private static char[]? s_otherCoreNewLine;

/// <summary>
/// This is the 'NewLine' property expressed as a char[].
/// It is exposed to subclasses as a protected field for read-only
Expand Down Expand Up @@ -112,8 +116,17 @@ public virtual string NewLine
{
value ??= Environment.NewLineConst;

CoreNewLineStr = value;
CoreNewLine = value.ToCharArray();
if (CoreNewLineStr != value)
{
CoreNewLineStr = value;
CoreNewLine =
value == Environment.NewLineConst ? s_coreNewLine : // current OS default
Environment.NewLineConst == "\r\n" && value == "\n" ? (s_otherCoreNewLine ??= ['\n']) : // other OS default
Environment.NewLineConst == "\n" && value == "\r\n" ? (s_otherCoreNewLine ??= ['\r', '\n']) : // other OS default
value.ToCharArray(); // unknown
Comment on lines +123 to +126
Copy link
Contributor

@GerardSmit GerardSmit Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a switch expression to improve readability?

Suggested change
value == Environment.NewLineConst ? s_coreNewLine : // current OS default
Environment.NewLineConst == "\r\n" && value == "\n" ? (s_otherCoreNewLine ??= ['\n']) : // other OS default
Environment.NewLineConst == "\n" && value == "\r\n" ? (s_otherCoreNewLine ??= ['\r', '\n']) : // other OS default
value.ToCharArray(); // unknown
CoreNewLine = (value, Environment.NewLineConst) switch
{
// current OS default
(Environment.NewLineConst, Environment.NewLineConst) => s_coreNewLine,
// other OS default
("\n", "\r\n") => s_otherCoreNewLine ??= ['\n'],
("\r\n", "\n") => s_otherCoreNewLine ??= ['\r', '\n'],
// unknown
_ => value.ToCharArray(),
};

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way I wrote it, the C# compiler will detect that some of the branches are dead and dead-code eliminate them, e.g. on Linux, the line that starts with Environment.NewLineConst == "\r\n" gets entirely removed by the C# compiler (because it sees "\n" == "\r\n"). That doesn't currently happen with the switch variant.

Copy link
Contributor

@GerardSmit GerardSmit Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see. With tuples Roslyn doesn't see that the branche is dead code.

With the following it does Sharplab / DiffChecker.

Suggested change
value == Environment.NewLineConst ? s_coreNewLine : // current OS default
Environment.NewLineConst == "\r\n" && value == "\n" ? (s_otherCoreNewLine ??= ['\n']) : // other OS default
Environment.NewLineConst == "\n" && value == "\r\n" ? (s_otherCoreNewLine ??= ['\r', '\n']) : // other OS default
value.ToCharArray(); // unknown
CoreNewLine = value switch
{
// other OS default
"\n" when Environment.NewLineConst == "\r\n" => s_otherCoreNewLine ??= ['\n'],
"\r\n" when Environment.NewLineConst == "\n" => s_otherCoreNewLine ??= ['\r', '\n'],
// current OS default
Environment.NewLineConst => s_coreNewLine,
// unknown
_ => value.ToCharArray(),
};

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, though I personally don't think that improves readability.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That doesn't currently happen with the switch variant.

File an issue?

}

Debug.Assert(CoreNewLineStr == new string(CoreNewLine));
}
}

Expand Down
Loading