Skip to content

Commit fb720d4

Browse files
authored
Ca1841 (#23887)
1 parent 70713fe commit fb720d4

File tree

4 files changed

+103
-0
lines changed

4 files changed

+103
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
---
2+
title: "CA1841: Prefer Dictionary Contains methods (code analysis)"
3+
description: "Learn about code analysis rule CA1841: Prefer Dictionary Contains methods"
4+
ms.date: 04/21/2021
5+
ms.topic: reference
6+
f1_keywords:
7+
- "PreferDictionaryContainsMethods"
8+
- "CA1841"
9+
helpviewer_keywords:
10+
- "PreferDictionaryContainsMethods"
11+
- "CA1841"
12+
author: NewellClark
13+
dev_langs:
14+
- CSharp
15+
- VB
16+
---
17+
# CA1841: Prefer Dictionary Contains methods
18+
19+
| | Value |
20+
|-|-|
21+
| **Rule ID** |CA1841|
22+
| **Category** |[Performance](performance-warnings.md)|
23+
| **Fix is breaking or non-breaking** |Non-breaking|
24+
25+
## Cause
26+
27+
This rule locates calls to a `Contains` method on the `Keys` or `Values` collection of an <xref:System.Collections.Generic.IDictionary%602> that could be replaced with a call to a `ContainsKey` or `ContainsValue` method on the dictionary itself.
28+
29+
## Rule description
30+
31+
Calling `Contains` on the `Keys` or `Values` collection can often be more expensive than calling `ContainsKey` or `ContainsValue` on the dictionary itself:
32+
33+
- Many dictionary implementations lazily instantiate the key and value collections, which means that accessing the `Keys` or `Values` collection may result in extra allocations.
34+
- You may end up calling an extension method on <xref:System.Collections.Generic.IEnumerable%601> if the keys or values collection uses explicit interface implementation to hide methods on <xref:System.Collections.Generic.ICollection%601>. This can lead to reduced performance, especially when accessing the key collection. Most dictionary implementations are able to provide a fast O(1) containment check for keys, while the `Contains` extension method on <xref:System.Collections.Generic.IEnumerable%601> usually does a slow O(n) containment check.
35+
36+
## How to fix violations
37+
38+
To fix violations, replace calls to `dictionary.Keys.Contains` or `dictionary.Values.Contains` with calls to `dictionary.ContainsKey` or `dictionary.ContainsValue`, respectively.
39+
40+
The following code snippet shows examples of violations, and how to fix them.
41+
42+
```csharp
43+
using System.Collections.Generic;
44+
// Importing this namespace brings extension methods for IEnumerable`1 into scope.
45+
using System.Linq;
46+
47+
class Example
48+
{
49+
void Method()
50+
{
51+
var dictionary = new Dictionary<string, int>();
52+
53+
// Violation
54+
dictionary.Keys.Contains("hello world");
55+
56+
// Fixed
57+
dictionary.ContainsKey("hello world");
58+
59+
// Violation
60+
dictionary.Values.Contains(17);
61+
62+
// Fixed
63+
dictionary.ContainsValue(17);
64+
}
65+
}
66+
```
67+
68+
```vb
69+
Imports System.Collection.Generic
70+
' Importing this namespace brings extension methods for IEnumerable`1 into scope.
71+
' Note that in Visual Basic, this namespace is often imported automatically throughout the project.
72+
Imports System.Linq
73+
74+
Class Example
75+
Private Sub Method()
76+
Dim dictionary = New Dictionary(Of String, Of Integer)
77+
78+
' Violation
79+
dictionary.Keys.Contains("hello world")
80+
81+
' Fixed
82+
dictionary.ContainsKey("hello world")
83+
84+
' Violation
85+
dictionary.Values.Contains(17)
86+
87+
' Fixed
88+
dictionary.ContainsValue(17)
89+
End Sub
90+
End Class
91+
```
92+
93+
## When to suppress warnings
94+
95+
It is safe to suppress warnings from this rule if the code in question is not performance-critical.
96+
97+
## See also
98+
99+
- [Performance rules](performance-warnings.md)

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ The following table lists code quality analysis rules.
129129
> |[CA1836: Prefer `IsEmpty` over `Count` when available](ca1836.md) | Prefer `IsEmpty` property that is more efficient than `Count`, `Length`, <xref:System.Linq.Enumerable.Count%60%601%28System.Collections.Generic.IEnumerable%7B%60%600%7D%29> or <xref:System.Linq.Enumerable.LongCount%60%601%28System.Collections.Generic.IEnumerable%7B%60%600%7D%29> to determine whether the object contains or not any items. |
130130
> | [CA1837: Use `Environment.ProcessId` instead of `Process.GetCurrentProcess().Id`](ca1837.md) | `Environment.ProcessId` is simpler and faster than `Process.GetCurrentProcess().Id`. |
131131
> | [CA1838: Avoid `StringBuilder` parameters for P/Invokes](ca1838.md) | Marshaling of 'StringBuilder' always creates a native buffer copy, resulting in multiple allocations for one marshaling operation. |
132+
> | [CA1841: Prefer Dictionary Contains methods](ca1841.md) | Calling `Contains` on the `Keys` or `Values` collection may often be more expensive than calling `ContainsKey` or `ContainsValue` on the dictionary itself. |
132133
> | [CA2000: Dispose objects before losing scope](ca2000.md) | Because an exceptional event might occur that will prevent the finalizer of an object from running, the object should be explicitly disposed before all references to it are out of scope. |
133134
> |[CA2002: Do not lock on objects with weak identity](ca2002.md) |An object is said to have a weak identity when it can be directly accessed across application domain boundaries. A thread that tries to acquire a lock on an object that has a weak identity can be blocked by a second thread in a different application domain that has a lock on the same object. |
134135
> | [CA2007: Do not directly await a Task](ca2007.md) | An asynchronous method [awaits](../../../csharp/language-reference/operators/await.md) a <xref:System.Threading.Tasks.Task> directly. When an asynchronous method awaits a <xref:System.Threading.Tasks.Task> directly, continuation occurs in the same thread that created the task. This behavior can be costly in terms of performance and can result in a deadlock on the UI thread. Consider calling <xref:System.Threading.Tasks.Task.ConfigureAwait(System.Boolean)?displayProperty=nameWithType> to signal your intention for continuation. |

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,4 @@ Performance rules support high-performance libraries and applications.
4949
| [CA1836: Prefer `IsEmpty` over `Count` when available](ca1836.md) | Prefer `IsEmpty` property that is more efficient than `Count`, `Length`, <xref:System.Linq.Enumerable.Count%60%601%28System.Collections.Generic.IEnumerable%7B%60%600%7D%29> or <xref:System.Linq.Enumerable.LongCount%60%601%28System.Collections.Generic.IEnumerable%7B%60%600%7D%29> to determine whether the object contains or not any items. |
5050
| [CA1837: Use `Environment.ProcessId` instead of `Process.GetCurrentProcess().Id`](ca1837.md) | `Environment.ProcessId` is simpler and faster than `Process.GetCurrentProcess().Id`. |
5151
| [CA1838: Avoid `StringBuilder` parameters for P/Invokes](ca1838.md) | Marshaling of `StringBuilder` always creates a native buffer copy, resulting in multiple allocations for one marshaling operation. |
52+
| [CA1841: Prefer Dictionary Contains methods](ca1841.md) | Calling `Contains` on the `Keys` or `Values` collection may often be more expensive than calling `ContainsKey` or `ContainsValue` on the dictionary itself. |

docs/fundamentals/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,8 @@ items:
776776
href: code-analysis/quality-rules/ca1837.md
777777
- name: CA1838
778778
href: code-analysis/quality-rules/ca1838.md
779+
- name: CA1841
780+
href: code-analysis/quality-rules/ca1841.md
779781
- name: Publish rules
780782
items:
781783
- name: Overview

0 commit comments

Comments
 (0)