CA1841: Dictionary Contains メソッドを優先する

プロパティ
ルール ID CA1841
Title Dictionary Contains メソッドを優先する
[カテゴリ] パフォーマンス
修正が中断ありか中断なしか なし
.NET 8 では既定で有効 提案として

原因

この規則では、IDictionary<TKey,TValue>Keys または Values コレクション上での Contains メソッドの呼び出しが特定されますが、その呼び出しは、ディクショナリ自体での ContainsKey または ContainsValue メソッドの呼び出しに置換されることがあります。

規則の説明

Keys または Values コレクションで Contains を呼び出すと、多くの場合、ディクショナリ自体で ContainsKey または ContainsValue を呼び出すよりも負荷が高くなることがあります。

  • 多くのディクショナリ実装では、キーと値のコレクションが遅延的にインスタンス化されます。つまり、Keys または Values コレクションにアクセスすると、余分な割り当てが発生することがあります。
  • キーまたは値のコレクションで、ICollection<T> でメソッドを隠す目的で明示的なインターフェイス実装が使用される場合、IEnumerable<T> で拡張メソッドを呼び出すことことになります。 その場合、パフォーマンスが低下することがあります。特に、キーのコレクションにアクセスするときはそれが顕著です。 ほとんどのディクショナリ実装では、キーに対して高速の O(1) コンテインメント チェックを提供できます。一方で、IEnumerable<T>Contains 拡張メソッドでは通常、低速の O(n) コンテインメント チェックが実行されます。

違反の修正方法

違反を修正するには、dictionary.Keys.Contains または dictionary.Values.Contains の呼び出しをそれぞれ、dictionary.ContainsKey または dictionary.ContainsValue の呼び出しに置き換えます。

次のコード スニペットは、違反の例とその修正方法を示しています。

using System.Collections.Generic;
// Importing this namespace brings extension methods for IEnumerable<T> into scope.
using System.Linq;

class Example
{
    void Method()
    {
        var dictionary = new Dictionary<string, int>();

        //  Violation
        dictionary.Keys.Contains("hello world");

        //  Fixed
        dictionary.ContainsKey("hello world");

        //  Violation
        dictionary.Values.Contains(17);

        //  Fixed
        dictionary.ContainsValue(17);
    }
}
Imports System.Collection.Generic
' Importing this namespace brings extension methods for IEnumerable(Of T) into scope.
' Note that in Visual Basic, this namespace is often imported automatically throughout the project.
Imports System.Linq

Class Example
    Private Sub Method()
        Dim dictionary = New Dictionary(Of String, Of Integer)

        ' Violation
        dictionary.Keys.Contains("hello world")

        ' Fixed
        dictionary.ContainsKey("hello world")

        ' Violation
        dictionary.Values.Contains(17)

        ' Fixed
        dictionary.ContainsValue(17)
    End Sub
End Class

どのようなときに警告を抑制するか

問題のコードがパフォーマンス上、重大ではない場合、この規則からの警告を非表示にしても問題ありません。

警告を抑制する

単一の違反を抑制するだけの場合は、ソース ファイルにプリプロセッサ ディレクティブを追加して無効にしてから、規則をもう一度有効にします。

#pragma warning disable CA1841
// The code that's violating the rule is on this line.
#pragma warning restore CA1841

ファイル、フォルダー、またはプロジェクトの規則を無効にするには、構成ファイルでその重要度を none に設定します。

[*.{cs,vb}]
dotnet_diagnostic.CA1841.severity = none

詳細については、「コード分析の警告を抑制する方法」を参照してください。

関連項目