use char instead of string for joins#4989
Conversation
There was a problem hiding this comment.
Code Review
Overall: This is a clean, consistent micro-optimization that aligns well with TUnit's "Performance First" principle. Approving the approach.
Why this is a good change
Using instead of avoids allocating a small object on the heap for each separator. Since was introduced in .NET 5 and TUnit targets , all overloads are unconditionally available — no compatibility concern whatsoever.
This is the same class of improvement as using '\n' vs "\n" or string.Contains('x') vs string.Contains("x"). Each individual allocation is tiny, but applied consistently across hot paths (e.g. type key building, method key lookup, filter parsing) it reduces GC pressure in aggregate.
Missed instances
Two call sites with single-char string separators were not updated:
-
TUnit.Mocks.SourceGenerator/Builders/MockMembersBuilder.cs:604— identical pattern to the three otherGetConstraintClausesmethods that were updated in this PR (MockImplBuilder,MockSetupBuilder,MockVerifyBuilder):// Current (missed) return clauses.Count > 0 ? " " + string.Join(" ", clauses) : ""; // Should be return clauses.Count > 0 ? " " + string.Join(' ', clauses) : "";
-
TUnit.TestProject/ConstraintKeyStressTests.cs:174:// Current (missed) $"Shared keys: {string.Join(",", currentKeys.Intersect(otherKeys))}, " // Should be $"Shared keys: {string.Join(',', currentKeys.Intersect(otherKeys))}, "
These are minor — the PR is already a net positive — but worth catching for completeness.
No architectural concerns
The change is purely mechanical (27 identical substitutions), functionally equivalent, and the diff is easy to review. No design issues.
There was a problem hiding this comment.
Code Review
Overall: This is a clean, consistent micro-optimization that aligns well with TUnit's "Performance First" principle.
Why this is a good change
Using string.Join(char, ...) instead of string.Join(string, ...) avoids allocating a small string object on the heap for each separator. Since the char overload was introduced in .NET 5 and TUnit targets net8.0;net9.0;net10.0, all overloads are unconditionally available — no compatibility concern.
This is the same class of improvement as using '\n' vs "\n" or string.Contains('x') vs string.Contains("x"). Each individual allocation is tiny, but applied consistently across hot paths (type key building, method key lookup, filter parsing) it reduces GC pressure in aggregate.
Missed instances
Two call sites with single-char string separators were not updated:
1. TUnit.Mocks.SourceGenerator/Builders/MockMembersBuilder.cs:604 — identical pattern to the three other GetConstraintClauses methods that were updated (MockImplBuilder, MockSetupBuilder, MockVerifyBuilder):
// Current (missed)
return clauses.Count > 0 ? " " + string.Join(" ", clauses) : "";
// Should be
return clauses.Count > 0 ? " " + string.Join(' ', clauses) : "";2. TUnit.TestProject/ConstraintKeyStressTests.cs:174:
// Current (missed)
$"Shared keys: {string.Join(",", currentKeys.Intersect(otherKeys))}, "
// Should be
$"Shared keys: {string.Join(',', currentKeys.Intersect(otherKeys))}, "These are minor — the PR is already a net positive — but worth catching for completeness.
No architectural concerns
The change is purely mechanical (27 identical substitutions), functionally equivalent, and the diff is easy to review. No design issues.
No description provided.