Skip to content

Commit a99b608

Browse files
authored
Add CA1862 and CA1863 (#38344)
1 parent 5e8a494 commit a99b608

File tree

5 files changed

+209
-0
lines changed

5 files changed

+209
-0
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
---
2+
title: "CA1862: Use the 'StringComparison' method overloads to perform case-insensitive string comparisons"
3+
description: "Learn about code analysis rule CA1862: Use the 'StringComparison' method overloads to perform case-insensitive string comparisons"
4+
ms.date: 11/21/2023
5+
f1_keywords:
6+
- "CA1862"
7+
helpviewer_keywords:
8+
- "CA1862"
9+
dev_langs:
10+
- CSharp
11+
- VB
12+
---
13+
14+
# CA1862: Use the 'StringComparison' method overloads to perform case-insensitive string comparisons
15+
16+
| Property | Value |
17+
|-------------------------------------|----------------------------------------|
18+
| **Rule ID** | CA1862 |
19+
| **Title** | Use the 'StringComparison' method overloads to perform case-insensitive string comparisons |
20+
| **Category** | [Performance](performance-warnings.md) |
21+
| **Fix is breaking or non-breaking** | Non-breaking |
22+
| **Enabled by default in .NET 8** | No |
23+
24+
## Cause
25+
26+
Code compares two strings in a case-insensitive manner by first calling <xref:System.String.ToLower>, <xref:System.String.ToLowerInvariant>, <xref:System.String.ToUpper>, or <xref:System.String.ToUpperInvariant> on one or both strings.
27+
28+
## Rule description
29+
30+
When code calls <xref:System.String.ToLower>, <xref:System.String.ToLowerInvariant>, <xref:System.String.ToUpper>, or <xref:System.String.ToUpperInvariant>, an allocation is performed. If the only reason for calling these methods is to perform a case-insensitive string comparison or search, the allocation is unnecessary. Instead, you can call a string comparison method that takes a <xref:System.StringComparison> and specify one of the `*IgnoreCase` values.
31+
32+
## How to fix violations
33+
34+
Remove the call to <xref:System.String.ToLower>, <xref:System.String.ToLowerInvariant>, <xref:System.String.ToUpper>, or <xref:System.String.ToUpperInvariant>, and either call one of the <xref:System.StringComparer> methods, or one of the following methods that takes a <xref:System.StringComparison> argument:
35+
36+
- <xref:System.String.Compare(System.String,System.String,System.StringComparison)?displayProperty=nameWithType>
37+
- <xref:System.String.Contains(System.String,System.StringComparison)?displayProperty=nameWithType>
38+
- <xref:System.String.EndsWith(System.String,System.StringComparison)?displayProperty=nameWithType>
39+
- <xref:System.String.Equals(System.String,System.StringComparison)?displayProperty=nameWithType>
40+
- <xref:System.String.IndexOf%2A?displayProperty=nameWithType>
41+
- <xref:System.String.LastIndexOf%2A?displayProperty=nameWithType>
42+
- <xref:System.String.Replace(System.String,System.String,System.StringComparison)?displayProperty=nameWithType>
43+
- <xref:System.String.StartsWith(System.String,System.StringComparison)?displayProperty=nameWithType>
44+
- <xref:System.Uri.Compare(System.Uri,System.Uri,System.UriComponents,System.UriFormat,System.StringComparison)>
45+
- <xref:Microsoft.Extensions.Primitives.StringSegment.Compare(Microsoft.Extensions.Primitives.StringSegment,Microsoft.Extensions.Primitives.StringSegment,System.StringComparison)?displayProperty=nameWithType>
46+
- <xref:Microsoft.Extensions.Primitives.StringSegment.EndsWith(System.String,System.StringComparison)?displayProperty=nameWithType>
47+
- <xref:Microsoft.Extensions.Primitives.StringSegment.Equals%2A?displayProperty=nameWithType>
48+
- <xref:Microsoft.Extensions.Primitives.StringSegment.StartsWith(System.String,System.StringComparison)?displayProperty=nameWithType>
49+
50+
> [!NOTE]
51+
>
52+
> - If you change your code to use an overload that takes a <xref:System.StringComparison> argument, it might cause subtle changes in behavior. It's important to conduct thorough testing if you make this change or accept the Visual Studio lightbulb suggestion.
53+
> - If the strings don't need to be compared in a culturally sensitive manner, consider passing <xref:System.StringComparison.OrdinalIgnoreCase?displayProperty=nameWithType>.
54+
55+
## Example
56+
57+
The following example shows a violation of the rule:
58+
59+
```csharp
60+
string s1 = "aBc";
61+
string s2 = "aBC";
62+
63+
int _ = s1.ToUpper().CompareTo(s2.ToUpper());
64+
```
65+
66+
```vb
67+
Dim s1 As String = "aBc"
68+
Dim s2 As String = "aBC"
69+
70+
Dim i As Integer = s1.ToUpper().CompareTo(s2.ToUpper())
71+
```
72+
73+
The following example shows code that fixes the violation:
74+
75+
```csharp
76+
string s1 = "aBc";
77+
string s2 = "aBC";
78+
79+
int _ = StringComparer.CurrentCultureIgnoreCase.Compare(s1, s2);
80+
```
81+
82+
```vb
83+
Dim s1 As String = "aBc"
84+
Dim s2 As String = "aBC"
85+
86+
Dim i As Integer = StringComparer.CurrentCultureIgnoreCase.Compare(s1, s2)
87+
```
88+
89+
## When to suppress warnings
90+
91+
It's safe to suppress warnings from this rule if performance isn't a concern.
92+
93+
## Suppress a warning
94+
95+
If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
96+
97+
```csharp
98+
#pragma warning disable CA1862
99+
// The code that's violating the rule is on this line.
100+
#pragma warning restore CA1862
101+
```
102+
103+
To disable the rule for a file, folder, or project, set its severity to `none` in the [configuration file](../configuration-files.md).
104+
105+
```ini
106+
[*.{cs,vb}]
107+
dotnet_diagnostic.CA1862.severity = none
108+
```
109+
110+
For more information, see [How to suppress code analysis warnings](../suppress-warnings.md).
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
---
2+
title: "CA1863: Use 'CompositeFormat'"
3+
description: "Learn about code analysis rule CA1863: Use 'CompositeFormat'"
4+
ms.date: 11/20/2023
5+
f1_keywords:
6+
- "CA1863"
7+
helpviewer_keywords:
8+
- "CA1863"
9+
---
10+
11+
# CA1863: Use 'CompositeFormat'
12+
13+
| Property | Value |
14+
|-------------------------------------|----------------------------------------|
15+
| **Rule ID** | CA1863 |
16+
| **Title** | Use `CompositeFormat` |
17+
| **Category** | [Performance](performance-warnings.md) |
18+
| **Fix is breaking or non-breaking** | Non-breaking |
19+
| **Enabled by default in .NET 8** | No |
20+
21+
## Cause
22+
23+
Code calls <xref:System.String.Format(System.String,System.Object[])?displayProperty=nameWithType> or <xref:System.Text.StringBuilder.AppendFormat(System.String,System.Object[])?displayProperty=nameWithType> with a `static` format string that hasn't been cached to a <xref:System.Text.CompositeFormat> instance.
24+
25+
## Rule description
26+
27+
It's expensive to parse a format string at run time. This rule locates places in your code where you can cache and use a <xref:System.Text.CompositeFormat> instance as the argument to a formatting operation, rather than passing in the original format string. A <xref:System.Text.CompositeFormat> instance parses the composite format string when it's created, which means the "hot path" of string formatting can execute much faster.
28+
29+
## How to fix violations
30+
31+
Create an instance of <xref:System.Text.CompositeFormat> by calling <xref:System.Text.CompositeFormat.Parse(System.String)?displayProperty=nameWithType> and pass it to <xref:System.String.Format(System.IFormatProvider,System.Text.CompositeFormat,System.Object[])?displayProperty=nameWithType> or <xref:System.Text.StringBuilder.AppendFormat(System.IFormatProvider,System.Text.CompositeFormat,System.Object[])?displayProperty=nameWithType> instead of the original format string.
32+
33+
## Example
34+
35+
The following example shows two violations of the rule:
36+
37+
```csharp
38+
class C
39+
{
40+
private static readonly string StaticField;
41+
42+
static void Main()
43+
{
44+
_ = string.Format(StaticField, 42);
45+
46+
StringBuilder sb = new();
47+
sb.AppendFormat(StaticField, 42);
48+
}
49+
}
50+
```
51+
52+
The following example shows code that fixes both violations:
53+
54+
```csharp
55+
class C
56+
{
57+
private static readonly string StaticField;
58+
59+
static void Main()
60+
{
61+
CompositeFormat cf = CompositeFormat.Parse(StaticField);
62+
_ = string.Format(null, cf, 42);
63+
64+
StringBuilder sb = new();
65+
sb.AppendFormat(null, cf, 42);
66+
}
67+
}
68+
```
69+
70+
## When to suppress warnings
71+
72+
It's safe to suppress diagnostics from this rule if performance isn't a concern.
73+
74+
## Suppress a warning
75+
76+
If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
77+
78+
```csharp
79+
#pragma warning disable CA1863
80+
// The code that's violating the rule is on this line.
81+
#pragma warning restore CA1863
82+
```
83+
84+
To disable the rule for a file, folder, or project, set its severity to `none` in the [configuration file](../configuration-files.md).
85+
86+
```ini
87+
[*.{cs,vb}]
88+
dotnet_diagnostic.CA1863.severity = none
89+
```
90+
91+
For more information, see [How to suppress code analysis warnings](../suppress-warnings.md).

docs/fundamentals/code-analysis/quality-rules/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ The following table lists code quality analysis rules.
163163
> | [CA1859: Use concrete types when possible for improved performance](ca1859.md) | Code uses interface types or abstract types, leading to unnecessary interface calls or virtual calls. |
164164
> | [CA1860: Avoid using 'Enumerable.Any()' extension method](ca1860.md) | It's more efficient and clearer to use `Length`, `Count`, or `IsEmpty` (if possible) than to call <xref:System.Linq.Enumerable.Any%2A?displayProperty=nameWithType> to determine whether a collection type has any elements. |
165165
> | [CA1861: Avoid constant arrays as arguments](ca1861.md) | Constant arrays passed as arguments are not reused which implies a performance overhead. Consider extracting them to 'static readonly' fields to improve performance. |
166+
> | [CA1862: Use the 'StringComparison' method overloads to perform case-insensitive string comparisons](ca1862.md) | When code calls <xref:System.String.ToLower> or <xref:System.String.ToUpper> to perform a case-insensitive string comparison, an unnecessary allocation is performed. |
167+
> | [CA1863: Use 'CompositeFormat'](ca1863.md) | To reduce the formatting cost, cache and use a <xref:System.Text.CompositeFormat> instance as the argument to `String.Format` or `StringBuilder.AppendFormat`. |
166168
> | [CA1864: Prefer the 'IDictionary.TryAdd(TKey, TValue)' method](ca1864.md) | Both <xref:System.Collections.Generic.Dictionary%602.ContainsKey(%600)?displayProperty=nameWithType> and <xref:System.Collections.Generic.Dictionary%602.Add%2A?displayProperty=nameWithType> perform a lookup, which is redundant. It's is more efficient to call <xref:System.Collections.Generic.Dictionary%602.TryAdd%2A?displayProperty=nameWithType>, which returns a `bool` indicating if the value was added or not. `TryAdd` doesn't overwrite the key's value if the key is already present. |
167169
> | [CA1865-CA1867: Use char overload](ca1865-ca1867.md) | The char overload is a better performing overload for a string with a single char. |
168170
> | [CA1868: Unnecessary call to 'Contains' for sets](ca1868.md) | Both <xref:System.Collections.Generic.ISet%601.Add(%600)?displayProperty=nameWithType> and <xref:System.Collections.Generic.ICollection%601.Remove(%600)?displayProperty=nameWithType> perform a lookup, which makes it redundant to call <xref:System.Collections.Generic.ICollection%601.Contains(%600)?displayProperty=nameWithType> beforehand. It's more efficient to call <xref:System.Collections.Generic.ISet%601.Add(%600)> or <xref:System.Collections.Generic.ICollection%601.Remove(%600)> directly, which returns a Boolean value indicating whether the item was added or removed. |

docs/fundamentals/code-analysis/quality-rules/performance-warnings.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ Performance rules support high-performance libraries and applications.
7171
| [CA1859: Use concrete types when possible for improved performance](ca1859.md) | Code uses interface types or abstract types, leading to unnecessary interface calls or virtual calls. |
7272
| [CA1860: Avoid using 'Enumerable.Any()' extension method](ca1860.md) | It's more efficient and clearer to use `Length`, `Count`, or `IsEmpty` (if possible) than to call <xref:System.Linq.Enumerable.Any%2A?displayProperty=nameWithType> to determine whether a collection type has any elements. |
7373
| [CA1861: Avoid constant arrays as arguments](ca1861.md) | Constant arrays passed as arguments are not reused which implies a performance overhead. Consider extracting them to 'static readonly' fields to improve performance. |
74+
| [CA1862: Use the 'StringComparison' method overloads to perform case-insensitive string comparisons](ca1862.md) | When code calls <xref:System.String.ToLower> or <xref:System.String.ToUpper> to perform a case-insensitive string comparison, an unnecessary allocation is performed. |
75+
| [CA1863: Use 'CompositeFormat'](ca1863.md) | To reduce the formatting cost, cache and use a <xref:System.Text.CompositeFormat> instance as the argument to `String.Format` or `StringBuilder.AppendFormat`. |
7476
| [CA1864: Prefer the 'IDictionary.TryAdd(TKey, TValue)' method](ca1864.md) | Both <xref:System.Collections.Generic.Dictionary%602.ContainsKey(%600)?displayProperty=nameWithType> and <xref:System.Collections.Generic.Dictionary%602.Add%2A?displayProperty=nameWithType> perform a lookup, which is redundant. It's is more efficient to call <xref:System.Collections.Generic.Dictionary%602.TryAdd%2A?displayProperty=nameWithType>, which returns a `bool` indicating if the value was added or not. `TryAdd` doesn't overwrite the key's value if the key is already present. |
7577
| [CA1865-CA1867: Use char overload](ca1865-ca1867.md) | The char overload is a better performing overload for a string with a single char. |
7678
| [CA1868: Unnecessary call to 'Contains' for sets](ca1868.md) | Both <xref:System.Collections.Generic.ISet%601.Add(%600)?displayProperty=nameWithType> and <xref:System.Collections.Generic.ICollection%601.Remove(%600)?displayProperty=nameWithType> perform a lookup, which makes it redundant to call <xref:System.Collections.Generic.ICollection%601.Contains(%600)?displayProperty=nameWithType> beforehand. It's more efficient to call <xref:System.Collections.Generic.ISet%601.Add(%600)> or <xref:System.Collections.Generic.ICollection%601.Remove(%600)> directly, which returns a Boolean value indicating whether the item was added or removed. |

docs/navigate/tools-diagnostics/toc.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,10 @@ items:
10121012
href: ../../fundamentals/code-analysis/quality-rules/ca1860.md
10131013
- name: CA1861
10141014
href: ../../fundamentals/code-analysis/quality-rules/ca1861.md
1015+
- name: CA1862
1016+
href: ../../fundamentals/code-analysis/quality-rules/ca1862.md
1017+
- name: CA1863
1018+
href: ../../fundamentals/code-analysis/quality-rules/ca1863.md
10151019
- name: CA1864
10161020
href: ../../fundamentals/code-analysis/quality-rules/ca1864.md
10171021
- name: CA1865-CA1867

0 commit comments

Comments
 (0)