Performance rules
Performance rules support high-performance libraries and applications.
In this section
Rule | Description |
---|---|
CA1802: Use Literals Where Appropriate | A field is declared static and read-only (Shared and ReadOnly in Visual Basic), and is initialized with a value that is computable at compile time. Because the value that is assigned to the targeted field is computable at compile time, change the declaration to a const (Const in Visual Basic) field so that the value is computed at compile time instead of at run time. |
CA1805: Do not initialize unnecessarily | The .NET runtime initializes all fields of reference types to their default values before running the constructor. In most cases, explicitly initializing a field to its default value is redundant, which adds to maintenance costs and may degrade performance (such as with increased assembly size). |
CA1806: Do not ignore method results | A new object is created but never used, or a method that creates and returns a new string is called and the new string is never used, or a Component Object Model (COM) or P/Invoke method returns an HRESULT or error code that is never used. |
CA1810: Initialize reference type static fields inline | When a type declares an explicit static constructor, the just-in-time (JIT) compiler adds a check to each static method and instance constructor of the type to make sure that the static constructor was previously called. Static constructor checks can decrease performance. |
CA1812: Avoid uninstantiated internal classes | An instance of an assembly-level type is not created by code in the assembly. |
CA1813: Avoid unsealed attributes | .NET provides methods for retrieving custom attributes. By default, these methods search the attribute inheritance hierarchy. Sealing the attribute eliminates the search through the inheritance hierarchy and can improve performance. |
CA1814: Prefer jagged arrays over multidimensional | A jagged array is an array whose elements are arrays. The arrays that make up the elements can be of different sizes, which can result in less wasted space for some sets of data. |
CA1815: Override equals and operator equals on value types | For value types, the inherited implementation of Equals uses the Reflection library and compares the contents of all fields. Reflection is computationally expensive, and comparing every field for equality might be unnecessary. If you expect users to compare or sort instances, or to use instances as hash table keys, your value type should implement Equals. |
CA1819: Properties should not return arrays | Arrays that are returned by properties are not write-protected, even if the property is read-only. To keep the array tamper-proof, the property must return a copy of the array. Typically, users will not understand the adverse performance implications of calling such a property. |
CA1820: Test for empty strings using string length | Comparing strings by using the String.Length property or the String.IsNullOrEmpty method is significantly faster than using Equals. |
CA1821: Remove empty finalizers | Whenever you can, avoid finalizers because of the additional performance overhead that is involved in tracking object lifetime. An empty finalizer incurs added overhead without any benefit. |
CA1822: Mark members as static | Members that do not access instance data or call instance methods can be marked as static (Shared in Visual Basic). After you mark the methods as static, the compiler will emit nonvirtual call sites to these members. This can give you a measurable performance gain for performance-sensitive code. |
CA1823: Avoid unused private fields | Private fields were detected that do not appear to be accessed in the assembly. |
CA1824: Mark assemblies with NeutralResourcesLanguageAttribute | The NeutralResourcesLanguage attribute informs the Resource Manager of the language that was used to display the resources of a neutral culture for an assembly. This improves lookup performance for the first resource that you load and can reduce your working set. |
CA1825: Avoid zero-length array allocations | Initializing a zero-length array leads to unnecessary memory allocation. Instead, use the statically allocated empty array instance by calling Array.Empty. The memory allocation is shared across all invocations of this method. |
CA1826: Use property instead of Linq Enumerable method | Enumerable LINQ method was used on a type that supports an equivalent, more efficient property. |
CA1827: Do not use Count/LongCount when Any can be used | Count or LongCount method was used where Any method would be more efficient. |
CA1828: Do not use CountAsync/LongCountAsync when AnyAsync can be used | CountAsync or LongCountAsync method was used where AnyAsync method would be more efficient. |
CA1829: Use Length/Count property instead of Enumerable.Count method | Count LINQ method was used on a type that supports an equivalent, more efficient Length or Count property. |
CA1830: Prefer strongly-typed Append and Insert method overloads on StringBuilder | Append and Insert provide overloads for multiple types beyond System.String. When possible, prefer the strongly-typed overloads over using ToString() and the string-based overload. |
CA1831: Use AsSpan instead of Range-based indexers for string when appropriate | When using a range-indexer on a string and implicitly assigning the value to a ReadOnlySpan<char> type, the method Substring will be used instead of Slice, which produces a copy of requested portion of the string. |
CA1832: Use AsSpan or AsMemory instead of Range-based indexers for getting ReadOnlySpan or ReadOnlyMemory portion of an array | When using a range-indexer on an array and implicitly assigning the value to a ReadOnlySpan<T> or ReadOnlyMemory<T> type, the method GetSubArray will be used instead of Slice, which produces a copy of requested portion of the array. |
CA1833: Use AsSpan or AsMemory instead of Range-based indexers for getting Span or Memory portion of an array | When using a range-indexer on an array and implicitly assigning the value to a Span<T> or Memory<T> type, the method GetSubArray will be used instead of Slice, which produces a copy of requested portion of the array. |
CA1834: Use StringBuilder.Append(char) for single character strings | StringBuilder has an Append overload that takes a char as its argument. Prefer calling the char overload to improve performance. |
CA1835: Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync' | 'Stream' has a 'ReadAsync' overload that takes a 'Memory<Byte>' as the first argument, and a 'WriteAsync' overload that takes a 'ReadOnlyMemory<Byte>' as the first argument. Prefer calling the memory based overloads, which are more efficient. |
CA1836: Prefer IsEmpty over Count when available |
Prefer IsEmpty property that is more efficient than Count , Length , Count<TSource>(IEnumerable<TSource>) or LongCount<TSource>(IEnumerable<TSource>) to determine whether the object contains or not any items. |
CA1837: Use Environment.ProcessId instead of Process.GetCurrentProcess().Id |
Environment.ProcessId is simpler and faster than Process.GetCurrentProcess().Id . |
CA1838: Avoid StringBuilder parameters for P/Invokes |
Marshalling of StringBuilder always creates a native buffer copy, resulting in multiple allocations for one marshalling operation. |
CA1839: Use Environment.ProcessPath instead of Process.GetCurrentProcess().MainModule.FileName | Environment.ProcessPath is simpler and faster than Process.GetCurrentProcess().MainModule.FileName . |
CA1840: Use Environment.CurrentManagedThreadId instead of Thread.CurrentThread.ManagedThreadId | Environment.CurrentManagedThreadId is more compact and efficient than Thread.CurrentThread.ManagedThreadId . |
CA1841: Prefer Dictionary Contains methods | Calling Contains on the Keys or Values collection may often be more expensive than calling ContainsKey or ContainsValue on the dictionary itself. |
CA1842: Do not use 'WhenAll' with a single task | Using WhenAll with a single task may result in performance loss. Await or return the task instead. |
CA1843: Do not use 'WaitAll' with a single task | Using WaitAll with a single task may result in performance loss. Await or return the task instead. |
CA1844: Provide memory-based overrides of async methods when subclassing 'Stream' | To improve performance, override the memory-based async methods when subclassing 'Stream'. Then implement the array-based methods in terms of the memory-based methods. |
CA1845: Use span-based 'string.Concat' | It is more efficient to use AsSpan and string.Concat , instead of Substring and a concatenation operator. |
CA1846: Prefer AsSpan over Substring |
AsSpan is more efficient than Substring . Substring performs an O(n) string copy, while AsSpan does not and has a constant cost. AsSpan also does not perform any heap allocations. |
CA1847: Use char literal for a single character lookup | Use String.Contains(char) instead of String.Contains(string) when searching for a single character. |
CA1848: Use the LoggerMessage delegates | For improved performance, use the LoggerMessage delegates. |
CA1849: Call async methods when in an async method | In a method which is already asynchronous, calls to other methods should be to their async versions, where they exist. |
CA1850: Prefer static HashData method over ComputeHash |
It's more efficient to use the static HashData method over creating and managing a HashAlgorithm instance to call ComputeHash . |
CA1851: Possible multiple enumerations of IEnumerable collection |
Possible multiple enumerations of IEnumerable collection. Consider using an implementation that avoids multiple enumerations. |
CA1852: Seal internal types | A type that's not accessible outside its assembly and has no subtypes within its containing assembly is not sealed. |
CA1853: Unnecessary call to 'Dictionary.ContainsKey(key)' | There's no need to guard Dictionary.Remove(key) with Dictionary.ContainsKey(key) . Dictionary<TKey,TValue>.Remove(TKey) already checks whether the key exists and doesn't throw if it doesn't exist. |
CA1854: Prefer the 'IDictionary.TryGetValue(TKey, out TValue)' method | Prefer 'TryGetValue' over a Dictionary indexer access guarded by a 'ContainsKey' check. 'ContainsKey' and the indexer both look up the key, so using 'TryGetValue' avoids the extra lookup. |
CA1855: Use Span<T>.Clear() instead of Span<T>.Fill() | It's more efficient to call Span<T>.Clear() than to call Span<T>.Fill(T) to fill the elements of the span with a default value. |
CA1856: Incorrect usage of ConstantExpected attribute | The ConstantExpectedAttribute attribute is not applied correctly on a parameter. |
CA1857: The parameter expects a constant for optimal performance | An invalid argument is passed to a parameter that's annotated with ConstantExpectedAttribute. |
CA1858: Use StartsWith instead of IndexOf | It's more efficient to call String.StartsWith than to call String.IndexOf to check whether a string starts with a given prefix. |
CA1859: Use concrete types when possible for improved performance | Code uses interface types or abstract types, leading to unnecessary interface calls or virtual calls. |
CA1860: Avoid using 'Enumerable.Any()' extension method | It's more efficient and clearer to use Length , Count , or IsEmpty (if possible) than to call Enumerable.Any to determine whether a collection type has any elements. |
CA1861: Avoid constant arrays as arguments | Constant arrays passed as arguments are not reused which implies a performance overhead. Consider extracting them to 'static readonly' fields to improve performance. |
CA1862: Use the 'StringComparison' method overloads to perform case-insensitive string comparisons | When code calls ToLower() or ToUpper() to perform a case-insensitive string comparison, an unnecessary allocation is performed. |
CA1863: Use 'CompositeFormat' | To reduce the formatting cost, cache and use a CompositeFormat instance as the argument to String.Format or StringBuilder.AppendFormat . |
CA1864: Prefer the 'IDictionary.TryAdd(TKey, TValue)' method | Both Dictionary<TKey,TValue>.ContainsKey(TKey) and Dictionary<TKey,TValue>.Add perform a lookup, which is redundant. It's is more efficient to call Dictionary<TKey,TValue>.TryAdd, 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. |
CA1865-CA1867: Use char overload | The char overload is a better performing overload for a string with a single char. |
CA1868: Unnecessary call to 'Contains' for sets | Both ISet<T>.Add(T) and ICollection<T>.Remove(T) perform a lookup, which makes it redundant to call ICollection<T>.Contains(T) beforehand. It's more efficient to call Add(T) or Remove(T) directly, which returns a Boolean value indicating whether the item was added or removed. |
CA1869: Cache and reuse 'JsonSerializerOptions' instances | Using a local instance of JsonSerializerOptions for serialization or deserialization can substantially degrade the performance of your application if your code executes multiple times, since System.Text.Json internally caches serialization-related metadata into the provided instance. |
CA1870: Use a cached 'SearchValues' instance | Using a cached SearchValues<T> instance is more efficient than passing values to 'IndexOfAny' or 'ContainsAny' directly. |
CA1871: Do not pass a nullable struct to 'ArgumentNullException.ThrowIfNull' | 'ArgumentNullException.ThrowIfNull' accepts an 'object', so passing a nullable struct might cause the value to be boxed. |
CA1872: Prefer 'Convert.ToHexString' and 'Convert.ToHexStringLower' over call chains based on 'BitConverter.ToString' | Use Convert.ToHexString or Convert.ToHexStringLower when encoding bytes to a hexadecimal string representation. These methods are more efficient and allocation-friendly than using BitConverter.ToString in combination with String.Replace to replace dashes and String.ToLower. |
Collaborate with us on GitHub
The source for this content can be found on GitHub, where you can also create and review issues and pull requests. For more information, see our contributor guide.