Skip to content

Expand SearchValues remarks with cached-instance guidance and worked examples - #12989

Open
MihaZupan with Copilot wants to merge 13 commits into
mainfrom
copilot/improve-searchvalues-documentation
Open

Expand SearchValues remarks with cached-instance guidance and worked examples#12989
MihaZupan with Copilot wants to merge 13 commits into
mainfrom
copilot/improve-searchvalues-documentation

Conversation

Copilot AI commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

The SearchValues and SearchValues<T> remarks were thin on when the type is actually the right tool. This adds use-case guidance and compilable samples covering char, byte, and string sets, plus clarification on when not to reach for SearchValues.

SearchValues<T> remarks

  • Added a method table mapping each MemoryExtensions search API to what it's for, and a "Common use cases" section covering escaping, validation, UTF-8 data, and multi-substring search.
  • Emphasized caching in a static readonly field, since instance creation is where the analysis cost is paid.
  • Noted that the benefit grows with set size: the ContainsAny/IndexOfAny overloads taking individual values stop at three, and passing a longer span of values is slower than a cached instance.
  • Added a thread-safety note.

SearchValues<T>.Contains remarks

  • Steered readers toward the span-searching methods; Contains in a loop can't vectorize. Listed the cases where a single-value test is legitimate.
  • For SearchValues<string>, clarified that Contains tests the whole value against the set — it's not a substring search — and that FrozenSet<string>.Contains is faster for that. SearchValues<string> is for multi-substring searching.

SearchValues.Create overload remarks

  • Byte overload: pointed at UTF-8 literals ("..."u8) to build the set without allocating a string.
  • String overload: documented that a single-value instance is a faster alternative to IndexOf(value, StringComparison), because the value is analyzed once at creation rather than per search.
private static readonly SearchValues<string> s_chunked =
    SearchValues.Create(["chunked"], StringComparison.OrdinalIgnoreCase);

// Equivalent to text.IndexOf("chunked", StringComparison.OrdinalIgnoreCase),
// but faster because the value is analyzed once when the instance is created.
public static int IndexOfChunked(ReadOnlySpan<char> text) => text.IndexOfAny(s_chunked);

Snippets

New compilable project at snippets/csharp/System.Buffers/SearchValues/Overview/ with five regions: an escaping loop driven by IndexOfAny, allowed-character validation via ContainsAnyExcept, UTF-8 delimiter search, multi-substring and single-substring SearchValues<string> search, and a \uXXXX decoder demonstrating the narrow case where Contains is correct.

Samples deliberately avoid anything that reads as a copy-pastable security check (no HTML/output escaping predicate), and each region is chosen so the API shown is genuinely the best fit — e.g. the escaping loop can't be expressed with SplitAny or ReplaceAny.


Internal previews

File Preview link
snippets/csharp/System.Buffers/SearchValues/Overview/searchvalues.cs Preview published page
xml/Microsoft.Extensions.DependencyInjection/ValidationLocalizationServiceCollectionExtensions.xml Preview published page
xml/Microsoft.Extensions.Validation.Localization/ValidationLocalizationOptions.xml Preview published page
xml/System.Buffers/SearchValues.xml Preview published page
[xml/System.Buffers/SearchValues1.xml](https://github.com/dotnet/dotnet-api-docs/blob/1fafa60401e03fcf46dd701153395e2c618d6f59/xml/System.Buffers/SearchValues1.xml) Preview published page

Copilot AI and others added 8 commits August 14, 2026 13:58
Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Comment thread xml/System.Buffers/SearchValues`1.xml Outdated
@MihaZupan

Copy link
Copy Markdown
Member

@copilot Replace the Host example with a method that checks if the input is a hex string.

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>

Copilot AI commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Replace the Host example with a method that checks if the input is a hex string.

Done in 2f843d8 — the validation sample is now IsHexString using ContainsAnyExcept over SearchValues.Create("0123456789ABCDEFabcdef").

Copilot AI requested a review from MihaZupan August 14, 2026 16:58
Comment thread snippets/csharp/System.Buffers/SearchValues/Overview/searchvalues.cs Outdated
@MihaZupan

Copy link
Copy Markdown
Member

@copilot Drop the "or example when escaping JSON, JavaScript, or console output" part. Let's avoid suggesting that any sample is doing sufficient validation for any specific use case.

Swap the sample order such that the hex example is before the encoding one.

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>

Copilot AI commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Drop the "or example when escaping JSON, JavaScript, or console output" part. Let's avoid suggesting that any sample is doing sufficient validation for any specific use case.

Swap the samp...

Done in e0a83b9 — dropped the "escaping JSON, JavaScript, or console output" phrasing and moved the hex validation sample ahead of the escaping one (in both the remarks and the snippet file).

Copilot AI requested a review from MihaZupan August 14, 2026 17:37
Comment thread snippets/csharp/System.Buffers/SearchValues/Overview/searchvalues.cs Outdated
Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Copilot AI requested a review from MihaZupan August 14, 2026 17:42
@MihaZupan
MihaZupan marked this pull request as ready for review August 14, 2026 17:42
@MihaZupan
MihaZupan requested a review from a team as a code owner August 14, 2026 17:42
Copilot AI lite review requested due to automatic review settings August 14, 2026 17:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR expands the API reference remarks for System.Buffers.SearchValues and System.Buffers.SearchValues<T> to provide clearer guidance on when to use cached SearchValues instances, which span-search APIs to prefer, and how to apply the APIs in common scenarios. It also adds a compilable snippet project with worked examples across char, byte, and string sets.

Changes:

  • Expanded SearchValues<T> and SearchValues remarks with usage guidance, method mapping, caching recommendations, and thread-safety notes.
  • Added detailed remarks for SearchValues<T>.Contains (including guidance for SearchValues<string> semantics).
  • Introduced a new snippet project with multiple regions demonstrating recommended patterns.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
xml/System.Buffers/SearchValues`1.xml Adds extensive markdown remarks for SearchValues<T> and its Contains method, with multiple referenced examples.
xml/System.Buffers/SearchValues.xml Updates remarks for the factory methods and adds example references for byte/char/string creation guidance.
snippets/csharp/System.Buffers/SearchValues/Overview/searchvalues.cs New snippet source containing multiple regions illustrating span searching, validation, UTF-8 delimiter search, substring search, and the narrow Contains use case.
snippets/csharp/System.Buffers/SearchValues/Overview/Project.csproj New snippet project to ensure examples compile in CI.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 28 to +31
<summary>Provides an immutable, read-only set of values optimized for efficient searching.
Instances are created by <see cref="M:System.Buffers.SearchValues.Create(System.ReadOnlySpan{System.Byte})" /> or <see cref="M:System.Buffers.SearchValues.Create(System.ReadOnlySpan{System.Char})" />.</summary>
<remarks>
<see cref="T:System.Buffers.SearchValues`1" /> instances are optimized for situations where the same set of values is frequently used for searching at run time.</remarks>
<format type="text/markdown"><![CDATA[
Comment on lines +35 to +37
<xref:System.Buffers.SearchValues%601> instances are optimized for situations where the same set of values is frequently used for searching at run time. When you create the instance, the runtime analyzes the values and picks a search algorithm that's specialized for that set, often using vectorized (SIMD) instructions. That analysis is done once, so create the instance once and cache it, typically in a `static readonly` field.

Passing a <xref:System.Buffers.SearchValues%601> to one of the searching methods on <xref:System.MemoryExtensions> is usually much faster than passing the values as a span, especially for larger sets of values. Searching a span for a set of values is the primary purpose of the type, so reach for the following methods first:

:::code language="csharp" source="~/snippets/csharp/System.Buffers/SearchValues/Overview/searchvalues.cs" id="SnippetContains":::

For a <xref:System.Buffers.SearchValues%601> of <xref:System.String>, this method tests whether the whole `value` is one of the strings in the set, using the <xref:System.StringComparison> that was specified when the instance was created. It doesn't perform a substring search. Such a lookup is slower than <xref:System.Collections.Frozen.FrozenSet%601.Contains%2A?displayProperty=nameWithType>, so only create a <xref:System.Buffers.SearchValues%601> of <xref:System.String> when you need to search a span for multiple substrings.
Comment on lines +26 to +30
<xref:System.Buffers.SearchValues%601> instances are optimized for situations where the same set of values is frequently used for searching at run time. Creating an instance is relatively expensive because the values are analyzed to pick a specialized, often vectorized, search algorithm. Create the instance once and cache it, typically in a `static readonly` field, then pass it to the <xref:System.MemoryExtensions> methods that search a span, such as <xref:System.MemoryExtensions.IndexOfAny%2A>, <xref:System.MemoryExtensions.IndexOfAnyExcept%2A>, <xref:System.MemoryExtensions.ContainsAny%2A>, and <xref:System.MemoryExtensions.ContainsAnyExcept%2A>.

:::code language="csharp" source="~/snippets/csharp/System.Buffers/SearchValues/Overview/searchvalues.cs" id="SnippetEscaping":::

For more use cases and examples, see <xref:System.Buffers.SearchValues%601>.
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