Skip to content

Clean up CollectionExpression and Select combined usage#12919

Merged
ToddGrun merged 1 commit into
mainfrom
dev/toddgrun/CleanupCollectionExpressionsAndSelect
Mar 18, 2026
Merged

Clean up CollectionExpression and Select combined usage#12919
ToddGrun merged 1 commit into
mainfrom
dev/toddgrun/CleanupCollectionExpressionsAndSelect

Conversation

@ToddGrun
Copy link
Copy Markdown

There were several locations that had an immutable array, called select on it (getting back an IEnumerable) and then did a collection expression on that to get back an array. Instead, add a SelectAsPlainArray extension method on ImmutableArray that does this more efficiently.

Old way allocates iterator from IEnumerable, intermediate arrays while calculating select, and then allocated final array New way: only allocates final array

I noticed this from a code review I was doing, and not from perf traces, so I don't have evidence that this will make a tangible difference, but every bit helps.

There were several locations that had an immutable array, called select on it (getting back an IEnumerable) and then did a collection expression on that to get back an array. Instead, add a SelectAsPlainArray extension method on ImmutableArray that does this more efficiently.

Old way allocates iterator from IEnumerable, intermediate arrays while calculating select, and then allocated final array
New way: only allocates final array

I noticed this from a code review I was doing, and not from perf traces, so I don't have evidence that this will make a tangible difference, but every bit helps.
@ToddGrun ToddGrun requested a review from a team as a code owner March 18, 2026 19:42
}

mappedChanges[razorDocumentUri.AbsoluteUri] = mappedEdits;
mappedChanges[razorDocumentUri.AbsoluteUri] = ImmutableCollectionsMarshal.AsArray(mappedEdits)!;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I trust that you know what you're doing, but my initial reaction to this is worry. Isn't this dangerous because the internal array came from a pool, and therefore could in theory be reused for something else before whatever is reading mappedChanges see it?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This would only be dangerous if mappedEdits (or it's underlying array) were released back to a pool before we used it. Or maybe I'm misunderstanding the concern?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

More likely I'm misunderstanding, I just worry seeing "unsafe" things in product code, not in vetted helper methods. You never know who is going to copy them in potentially bad ways.

Comment on lines +93 to +97
var edits = new SumType<TextEdit, AnnotatedTextEdit>[textEdits.Length];
for (var i = 0; i < textEdits.Length; i++)
{
edits[i] = textEdits[i];
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Second time I've seen this pattern in the PR. Consider a CastAsPlainArray<T> extension?

Copy link
Copy Markdown
Author

@ToddGrun ToddGrun Mar 18, 2026

Choose a reason for hiding this comment

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

I gave it a quick go and it didn't seem to flow. I'm going to pass on this one unless you feel strongly, or have something in mind and coded up.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not at all, merge at will.

@davidwengier
Copy link
Copy Markdown
Member

You know what would be a great addition to this? An analyzer in Razor.Diagnostics.Analyzers so I don't make these mistakes again.

@ToddGrun
Copy link
Copy Markdown
Author

That would be my first analyzer, which would be kinda cool. I'll put this on my backlog, as it does sound interesting, but there are probably bigger fish to fry right now.


In reply to: 4085507970

@davidwengier
Copy link
Copy Markdown
Member

I've never written an analyzer from scratch either, but I have told copilot to do it, and it does a pretty good job :)

@ToddGrun ToddGrun merged commit bd9d77d into main Mar 18, 2026
10 checks passed
@ToddGrun ToddGrun deleted the dev/toddgrun/CleanupCollectionExpressionsAndSelect branch March 18, 2026 22:41
@dotnet-policy-service dotnet-policy-service Bot added this to the Next milestone Mar 18, 2026
@jjonescz jjonescz modified the milestones: Next, 18.6 Mar 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants