Skip to content

Commit 8626d2d

Browse files
BillWagnerCam Soper
andauthored
Freshen string comparison code (#44736)
* Move and update all code * Fixes #28006 Add an example that checks equality of instance delegates to point out that the receivers must be the same for those methods. * Equate `==` with the `is` pattern matching To fix #42548, create links between the equality operator and the pattern matching `is` expression, in the case where the right operand is a constant. In addition, add notes in the "How to compare strings" article to bring these together. * Add more overloads Fixes #20123 Add additional overloads as necessary, and explain the settings that can be applied among the different overloads. * final edit pass * Apply suggestions from code review Co-authored-by: Cam Soper <[email protected]> * respond to feedback. --------- Co-authored-by: Cam Soper <[email protected]>
1 parent 67cb1b4 commit 8626d2d

23 files changed

+1017
-932
lines changed

docs/csharp/how-to/compare-strings.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: "How to compare strings"
33
description: Learn how to compare and order string values, with or without case, with or without culture specific ordering.
4-
ms.date: 03/15/2024
4+
ms.date: 02/18/2025
55
helpviewer_keywords:
66
- "strings [C#], comparison"
77
- "comparing strings [C#]"
@@ -11,7 +11,7 @@ helpviewer_keywords:
1111

1212
You compare strings to answer one of two questions: "Are these two strings equal?" or "In what order should these strings be placed when sorting them?"
1313

14-
Those two questions are complicated by factors that affect string comparisons:
14+
The following factors complicate these two questions:
1515

1616
- You can choose an ordinal or linguistic comparison.
1717
- You can choose if case matters.
@@ -38,34 +38,36 @@ By default, the most common operations:
3838
- <xref:System.String.Equals%2A?displayProperty=nameWithType>
3939
- <xref:System.String.op_Equality%2A?displayProperty=nameWithType> and <xref:System.String.op_Inequality%2A?displayProperty=nameWithType>, that is, [equality operators `==` and `!=`](../language-reference/operators/equality-operators.md#string-equality), respectively perform a case-sensitive, ordinal comparison. <xref:System.String.Equals%2A?displayProperty=nameWithType> has an overload where a <xref:System.StringComparison> argument can be provided to alter its sorting rules. The following example demonstrates that:
4040

41-
:::code language="csharp" interactive="try-dotnet-method" source="../../../samples/snippets/csharp/how-to/strings/CompareStrings.cs" id="Snippet1":::
41+
:::code language="csharp" interactive="try-dotnet-method" source="./snippets/strings/CompareStrings.cs" id="Snippet1":::
4242

4343
The default ordinal comparison doesn't take linguistic rules into account when comparing strings. It compares the binary value of each <xref:System.Char> object in two strings. As a result, the default ordinal comparison is also case-sensitive.
4444

4545
The test for equality with <xref:System.String.Equals%2A?displayProperty=nameWithType> and the `==` and `!=` operators differs from string comparison using the <xref:System.String.CompareTo%2A?displayProperty=nameWithType> and <xref:System.String.Compare(System.String,System.String)?displayProperty=nameWithType)> methods. They all perform a case-sensitive comparison. However, while the tests for equality perform an ordinal comparison, the `CompareTo` and `Compare` methods perform a culture-aware linguistic comparison using the current culture. Make the intent of your code clear by calling an overload that explicitly specifies the type of comparison to perform.
4646

47+
You can use the [`is`](../language-reference/operators/is.md) operator and a [constant pattern](../language-reference/operators/patterns.md#constant-pattern) as an alternative to `==` when the right operand is a constant.
48+
4749
## Case-insensitive ordinal comparisons
4850

4951
The <xref:System.String.Equals(System.String,System.StringComparison)?displayProperty=nameWithType> method enables you to specify a <xref:System.StringComparison> value of
5052
<xref:System.StringComparison.OrdinalIgnoreCase?displayProperty=nameWithType> for a case-insensitive ordinal comparison. There's also a static <xref:System.String.Compare(System.String,System.String,System.StringComparison)?displayProperty=nameWithType> method that performs a case-insensitive ordinal comparison if you specify a value of <xref:System.StringComparison.OrdinalIgnoreCase?displayProperty=nameWithType> for the <xref:System.StringComparison> argument. These comparisons are shown in the following code:
5153

52-
:::code language="csharp" interactive="try-dotnet-method" source="../../../samples/snippets/csharp/how-to/strings/CompareStrings.cs" id="Snippet2":::
54+
:::code language="csharp" interactive="try-dotnet-method" source="./snippets/strings/CompareStrings.cs" id="Snippet2":::
5355

5456
These methods use the casing conventions of the [invariant culture](xref:System.Globalization.CultureInfo.InvariantCulture) when performing a case-insensitive ordinal comparison.
5557

5658
## Linguistic comparisons
5759

5860
Many string comparison methods (such as <xref:System.String.StartsWith%2A?displayProperty=nameWithType>) use linguistic rules for the _current culture_ by default to order their inputs. This linguistic comparison is sometimes referred to as "word sort order." When you perform a linguistic comparison, some nonalphanumeric Unicode characters might have special weights assigned. For example, the hyphen "-" might have a small weight assigned to it so that "co-op" and "coop" appear next to each other in sort order. Some nonprinting control characters might be ignored. In addition, some Unicode characters might be equivalent to a sequence of <xref:System.Char> instances. The following example uses the phrase "They dance in the street." in German with the "ss" (U+0073 U+0073) in one string and 'ß' (U+00DF) in another. Linguistically (in Windows), "ss" is equal to the German Esszet: 'ß' character in both the "en-US" and "de-DE" cultures.
5961

60-
:::code language="csharp" interactive="try-dotnet-method" source="../../../samples/snippets/csharp/how-to/strings/CompareStrings.cs" id="Snippet3":::
62+
:::code language="csharp" interactive="try-dotnet-method" source="./snippets/strings/CompareStrings.cs" id="Snippet3":::
6163

62-
On Windows, prior to .NET 5, the sort order of "cop", "coop", and "co-op" changes when you change from a linguistic comparison to an ordinal comparison. The two German sentences also compare differently using the different comparison types. Prior to .NET 5, the .NET globalization APIs used [National Language Support (NLS)](/windows/win32/intl/national-language-support) libraries. In .NET 5 and later versions, the .NET globalization APIs use [International Components for Unicode (ICU)](https://icu.unicode.org/) libraries, which unifies .NET's globalization behavior across all supported operating systems.
64+
On Windows, before .NET 5, the sort order of "cop", "coop", and "co-op" changes when you change from a linguistic comparison to an ordinal comparison. The two German sentences also compare differently using the different comparison types. Before .NET 5, the .NET globalization APIs used [National Language Support (NLS)](/windows/win32/intl/national-language-support) libraries. In .NET 5 and later versions, the .NET globalization APIs use [International Components for Unicode (ICU)](https://icu.unicode.org/) libraries, which unify .NET's globalization behavior across all supported operating systems.
6365

6466
## Comparisons using specific cultures
6567

6668
The following example stores <xref:System.Globalization.CultureInfo> objects for the en-US and de-DE cultures. The comparisons are performed using a <xref:System.Globalization.CultureInfo> object to ensure a culture-specific comparison. The culture used affects linguistic comparisons. The following example shows the results of comparing the two German sentences using the "en-US" culture and the "de-DE" culture:
6769

68-
:::code language="csharp" interactive="try-dotnet-method" source="../../../samples/snippets/csharp/how-to/strings/CompareStrings.cs" id="Snippet4":::
70+
:::code language="csharp" interactive="try-dotnet-method" source="./snippets/strings/CompareStrings.cs" id="Snippet4":::
6971

7072
Culture-sensitive comparisons are typically used to compare and sort strings input by users with other strings input by users. The characters and sorting conventions of these strings might vary depending on the locale of the user's computer. Even strings that contain identical characters might sort differently depending on the culture of the current thread.
7173

@@ -75,21 +77,21 @@ The following examples show how to sort and search for strings in an array using
7577

7678
The following example shows how to sort an array of strings using the current culture:
7779

78-
:::code language="csharp" interactive="try-dotnet-method" source="../../../samples/snippets/csharp/how-to/strings/CompareStrings.cs" id="Snippet5":::
80+
:::code language="csharp" interactive="try-dotnet-method" source="./snippets/strings/CompareStrings.cs" id="Snippet5":::
7981

8082
Once the array is sorted, you can search for entries using a binary search. A binary search starts in the middle of the collection to determine which half of the collection would contain the sought string. Each subsequent comparison subdivides the remaining part of the collection in half. The array is sorted using the <xref:System.StringComparer.CurrentCulture?displayProperty=nameWithType>. The local function `ShowWhere` displays information about where the string was found. If the string wasn't found, the returned value indicates where it would be if it were found.
8183

82-
:::code language="csharp" interactive="try-dotnet-method" source="../../../samples/snippets/csharp/how-to/strings/CompareStrings.cs" id="Snippet6":::
84+
:::code language="csharp" interactive="try-dotnet-method" source="./snippets/strings/CompareStrings.cs" id="Snippet6":::
8385

8486
## Ordinal sorting and searching in collections
8587

8688
The following code uses the <xref:System.Collections.Generic.List%601?displayProperty=nameWithType> collection class to store strings. The strings are sorted using the <xref:System.Collections.Generic.List%601.Sort%2A?displayProperty=nameWithType> method. This method needs a delegate that compares and orders two strings. The <xref:System.String.CompareTo%2A?displayProperty=nameWithType> method provides that comparison function. Run the sample and observe the order. This sort operation uses an ordinal case-sensitive sort. You would use the static <xref:System.String.Compare%2A?displayProperty=nameWithType> methods to specify different comparison rules.
8789

88-
:::code language="csharp" interactive="try-dotnet-method" source="../../../samples/snippets/csharp/how-to/strings/CompareStrings.cs" id="Snippet7":::
90+
:::code language="csharp" interactive="try-dotnet-method" source="./snippets/strings/CompareStrings.cs" id="Snippet7":::
8991

9092
Once sorted, the list of strings can be searched using a binary search. The following sample shows how to search the sorted list using the same comparison function. The local function `ShowWhere` shows where the sought text is or would be:
9193

92-
:::code language="csharp" interactive="try-dotnet-method" source="../../../samples/snippets/csharp/how-to/strings/CompareStrings.cs" id="Snippet8":::
94+
:::code language="csharp" interactive="try-dotnet-method" source="./snippets/strings/CompareStrings.cs" id="Snippet8":::
9395

9496
Always make sure to use the same type of comparison for sorting and searching. Using different comparison types for sorting and searching produces unexpected results.
9597

docs/csharp/how-to/concatenate-multiple-strings.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: "How to concatenate multiple strings"
33
description: There are multiple ways to concatenate strings in C#. Learn the options and the reasons behind different choices.
4-
ms.date: 1/31/2025
4+
ms.date: 02/18/2025
55
helpviewer_keywords:
66
- "joining strings [C#]"
77
- "concatenating strings [C#]"
@@ -22,19 +22,19 @@ ms.custom: copilot-scenario-highlight
2222

2323
The following example splits a long string literal into smaller strings to improve readability in the source code. The code concatenates the smaller strings to create the long string literal. The parts are concatenated into a single string at compile time. There's no run-time performance cost regardless of the number of strings involved.
2424

25-
:::code language="csharp" interactive="try-dotnet-method" source="../../../samples/snippets/csharp/how-to/strings/Concatenate.cs" id="Snippet1":::
25+
:::code language="csharp" interactive="try-dotnet-method" source="./snippets/strings/Concatenate.cs" id="Snippet1":::
2626

2727
## `+` and `+=` operators
2828

2929
To concatenate string variables, you can use the `+` or `+=` operators, [string interpolation](../language-reference/tokens/interpolated.md) or the <xref:System.String.Format%2A?displayProperty=nameWithType>, <xref:System.String.Concat%2A?displayProperty=nameWithType>, <xref:System.String.Join%2A?displayProperty=nameWithType> or <xref:System.Text.StringBuilder.Append%2A?displayProperty=nameWithType> methods. The `+` operator is easy to use and makes for intuitive code. Even if you use several `+` operators in one statement, the string content is copied only once. The following code shows examples of using the `+` and `+=` operators to concatenate strings:
3030

31-
:::code language="csharp" interactive="try-dotnet-method" source="../../../samples/snippets/csharp/how-to/strings/Concatenate.cs" id="Snippet2":::
31+
:::code language="csharp" interactive="try-dotnet-method" source="./snippets/strings/Concatenate.cs" id="Snippet2":::
3232

3333
## String interpolation
3434

3535
In some expressions, it's easier to concatenate strings using string interpolation, as the following code shows:
3636

37-
:::code language="csharp" interactive="try-dotnet-method" source="../../../samples/snippets/csharp/how-to/strings/Concatenate.cs" id="Snippet3":::
37+
:::code language="csharp" interactive="try-dotnet-method" source="./snippets/strings/Concatenate.cs" id="Snippet3":::
3838

3939
> [!NOTE]
4040
> In string concatenation operations, the C# compiler treats a null string the same as an empty string.
@@ -43,21 +43,21 @@ You can use string interpolation to initialize a constant string when all the ex
4343

4444
## `String.Format`
4545

46-
Another method to concatenate strings is <xref:System.String.Format%2A?displayProperty=nameWithType>. This method works well when you're building a string from a small number of component strings.
46+
Another method to concatenate strings is <xref:System.String.Format%2A?displayProperty=nameWithType>. This method works well when you're building a string from a few component strings.
4747

4848
## `StringBuilder`
4949

50-
In other cases, you might be combining strings in a loop where you don't know how many source strings you're combining, and the actual number of source strings can be large. The <xref:System.Text.StringBuilder> class was designed for these scenarios. The following code uses the <xref:System.Text.StringBuilder.Append%2A> method of the <xref:System.Text.StringBuilder> class to concatenate strings.
50+
In other cases, you might be combining strings in a loop where the actual number of source strings can be large. The <xref:System.Text.StringBuilder> class was designed for these scenarios. The following code uses the <xref:System.Text.StringBuilder.Append%2A> method of the <xref:System.Text.StringBuilder> class to concatenate strings.
5151

52-
:::code language="csharp" interactive="try-dotnet-method" source="../../../samples/snippets/csharp/how-to/strings/Concatenate.cs" id="Snippet4":::
52+
:::code language="csharp" interactive="try-dotnet-method" source="./snippets/strings/Concatenate.cs" id="Snippet4":::
5353

5454
You can read more about the [reasons to choose string concatenation or the `StringBuilder` class](/dotnet/api/system.text.stringbuilder#the-string-and-stringbuilder-types).
5555

5656
## `String.Concat` or `String.Join`
5757

5858
Another option to join strings from a collection is to use <xref:System.String.Concat%2A?displayProperty=nameWithType> method. Use <xref:System.String.Join%2A?displayProperty=nameWithType> method if a delimiter should separate source strings. The following code combines an array of words using both methods:
5959

60-
:::code language="csharp" interactive="try-dotnet-method" source="../../../samples/snippets/csharp/how-to/strings/Concatenate.cs" id="Snippet5":::
60+
:::code language="csharp" interactive="try-dotnet-method" source="./snippets/strings/Concatenate.cs" id="Snippet5":::
6161

6262
## LINQ and `Enumerable.Aggregate`
6363

@@ -67,7 +67,7 @@ the source strings using a lambda expression. The lambda expression does the
6767
work to add each string to the existing accumulation. The following example
6868
combines an array of words, adding a space between each word in the array:
6969

70-
:::code language="csharp" interactive="try-dotnet-method" source="../../../samples/snippets/csharp/how-to/strings/Concatenate.cs" id="Snippet6":::
70+
:::code language="csharp" interactive="try-dotnet-method" source="./snippets/strings/Concatenate.cs" id="Snippet6":::
7171

7272
This option can cause more allocations than other methods for concatenating collections, as it creates an intermediate string for each iteration. If optimizing performance is critical, consider the [`StringBuilder`](#stringbuilder) class or the [`String.Concat` or `String.Join`](#stringconcat-or-stringjoin) method to concatenate a collection, instead of `Enumerable.Aggregate`.
7373

0 commit comments

Comments
 (0)