性能规则
性能规则支持高性能库和应用程序。
在本节中
规则 | 描述 |
---|---|
CA1802:在合适的位置使用文本 | 某个字段被声明为 static 和 read-only(在 Visual Basic 中为 Shared 和 ReadOnly),并使用可在编译时计算的值初始化。 因为赋给目标字段的值可在编译时计算,因此请将声明更改为 const(在 Visual Basic 中为 Const)字段,以便在编译时而非运行时计算值。 |
CA1805:避免进行不必要的初始化 | 在运行构造函数之前,.NET 运行时将引用类型的所有字段初始化为其默认值。 在大多数情况下,将字段显式初始化为其默认值是多余的,这会增加维护成本,并可能会降低性能(例如随着程序集大小的增加)。 |
CA1806:不要忽略方法结果 | 创建一个新对象,但从不使用该对象;或者调用会创建并返回一个新字符串的方法,但从不使用这个新字符串;或者组件对象模型 (COM) 或 P/Invoke 方法返回一个从不使用的 HRESULT 或错误代码。 |
CA1810:以内联方式初始化引用类型的静态字段 | 当一个类型声明显式静态构造函数时,实时 (JIT) 编译器会向该类型的每个静态方法和实例构造函数中添加一项检查,以确保之前已调用该静态构造函数。 静态构造函数检查会降低性能。 |
CA1812:避免未实例化的内部类 | 程序集级别类型的实例不是由程序集中的代码创建的。 |
CA1813:避免使用非密封特性 | .NET 提供用于检索自定义属性的方法。 默认情况下,这些方法搜索特性继承层次结构。 通过密封特性,将无需搜索继承层次结构,且能够提高性能。 |
CA1814:与多维数组相比,首选使用交错数组 | 交错数组是元素为数组的数组。 构成元素的数组可采用不同的大小,使某些数据集浪费的空间减少。 |
CA1815:重写值类型上的 Equals 和相等运算符 | 对于值类型,Equals 的继承的实现使用反射库,并比较所有字段的内容。 反射需要消耗大量计算资源,可能没有必要比较每一个字段是否相等。 如果希望用户对实例进行比较或排序,或者希望用户将实例用作哈希表键,则值类型应实现 Equals。 |
CA1819:属性不应返回数组 | 即使属性是只读的,该属性返回的数组也不受写入保护。 若要使数组不会被更改,属性必须返回数组的副本。 通常,用户不能理解调用这种属性的负面性能影响。 |
CA1820:使用字符串长度测试是否有空字符串 | 使用 String.Length 属性或 String.IsNullOrEmpty 方法比较字符串要比使用 Equals 的速度快得多。 |
CA1821:移除空终结器 | 应尽可能避免终结器,因为跟踪对象生存期会产生额外的性能系统开销。 空的终结器只会徒增开销,没有一点好处。 |
CA1822:将成员标记为 static | 可以将不访问实例数据或不调用实例方法的成员标记为 static(在 Visual Basic 中为 Shared)。 在将这些方法标记为 static 之后,编译器将向这些成员发出非虚拟调用站点。 这会使性能敏感的代码的性能得到显著提高。 |
CA1823:避免未使用的私有字段 | 检测到程序集内有似乎未访问过的私有字段。 |
CA1824:用 NeutralResourcesLanguageAttribute 标记程序集 | NeutralResourcesLanguage 属性通知资源管理器用于显示程序集的非特定区域性资源的语言。 这将改进所加载的第一个资源的查找性能,并缩小工作集。 |
CA1825:避免数组分配长度为零 | 初始化长度为零的数组将导致不必要的内存分配。 相反,请通过调用 Array.Empty 来使用静态分配的空数组实例。 内存分配在此方法的所有调用之间共享。 |
CA1826:使用属性,而不是 Linq Enumerable 方法 | 对支持等效且更有效的属性的类型使用了 Enumerable LINQ 方法。 |
CA1827:如果可以使用 Any,请勿使用 Count/LongCount | 在使用 Any 方法会更有效的情况下使用了 Count 或 LongCount 方法。 |
CA1828:如果可以使用 AnyAsync,请勿使用 CountAsync/LongCountAsync | 在使用 AnyAsync 方法会更有效的情况下使用了 CountAsync 或 LongCountAsync 方法。 |
CA1829:使用 Length/Count 属性,而不是 Enumerable.Count 方法 | 对支持等效且更有效的 Length 或 Count 属性的类型使用了 Count LINQ 方法。 |
CA1830:在 StringBuilder 上优先使用强类型“追加和插入”方法重载 | Append 和 Insert 为除 System.String 之外的多种类型提供重载。 如果可能,首选强类型重载,而非 ToString () 和基于字符串的重载。 |
CA1831:在合适的情况下,为字符串使用 AsSpan 而不是基于范围的索引器 | 对字符串使用范围索引器并向 ReadOnlySpan<char> 类型隐式赋值时,将使用方法 Substring 而非 Slice,这会生成字符串请求部分的副本。 |
CA1832:使用 AsSpan 或 AsMemory 而不是基于范围的索引器来获取数组的 ReadOnlySpan 或 ReadOnlyMemory 部分 | 对字符串使用范围索引器并向 ReadOnlySpan<T> 或 ReadOnlyMemory<T> 类型隐式赋值时,将使用方法 GetSubArray 而非 Slice,这会生成数组请求部分的副本。 |
CA1833:使用 AsSpan 或 AsMemory 而不是基于范围的索引器来获取数组的 Span 或 Memory 部分 | 对字符串使用范围索引器并向 Span<T> 或 Memory<T> 类型隐式赋值时,将使用方法 GetSubArray 而非 Slice,这会生成数组请求部分的副本。 |
CA1834:对单字符字符串使用 StringBuilder.Append(char) | StringBuilder 具有将 char 用作其参数的 Append 重载。 优先选择调用 char 重载以提高性能。 |
CA1835:对于“ReadAsync”和“WriteAsync”,首选基于“Memory”的重载 | “Stream”有一个将“Memory<byte>”用作第一个参数的“ReadAsync”重载和一个将“ReadOnlyMemory<Byte>”用作第一个参数的“WriteAsync”重载。 优先选择调用基于内存的重载,它们更有效。 |
CA1836:如可用,首选 IsEmpty 而不是 Count |
首选比 Count 、Length 、Count<TSource>(IEnumerable<TSource>) 或 LongCount<TSource>(IEnumerable<TSource>) 更有效的 IsEmpty 属性,以确定对象是否包含任何项目。 |
CA1837:使用 Environment.ProcessId 而不是 Process.GetCurrentProcess().Id |
Environment.ProcessId 比 Process.GetCurrentProcess().Id 更简单、更快速。 |
CA1838:避免对 P/Invokes 使用 StringBuilder 参数 |
StringBuilder 的封送处理总是会创建一个本机缓冲区副本,这会导致一个封送处理操作出现多次分配。 |
CA1839:使用 Environment.ProcessPath 而不是 Process.GetCurrentProcess().MainModule.FileName | Environment.ProcessPath 比 Process.GetCurrentProcess().MainModule.FileName 更简单、更快速。 |
CA1840:使用 Environment.CurrentManagedThreadId 而不是 Thread.CurrentThread.ManagedThreadId | Environment.CurrentManagedThreadId 比 Thread.CurrentThread.ManagedThreadId 更紧凑、更高效。 |
CA1841:首选字典包含方法 | 对 Keys 或 Values 集合调用 Contains 通常比对字典本身调用 ContainsKey 或 ContainsValue 开销更高。 |
CA1842:不要对单个任务使用“WhenAll” | 对单个任务使用 WhenAll 可能会导致性能损失。 请改为等待或返回任务。 |
CA1843:不要对单个任务使用“WaitAll” | 对单个任务使用 WaitAll 可能会导致性能损失。 请改为等待或返回任务。 |
CA1844:对“流”进行子分类时,提供异步方法的基于内存的重写 | 若要提高性能,请在对“流”进行子分类时重写基于内存的异步方法。 然后,在基于内存的方法中实现基于数组的方法。 |
CA1845:使用基于跨度的“string.Concat” | 使用 AsSpan 和 string.Concat 比使用 Substring 和串联运算符更高效。 |
CA1846:首选 AsSpan ,次选 Substring |
AsSpan 比 Substring 更高效。 Substring 执行 O(n) 字符串复制,而 AsSpan 不会执行此操作且具有固定成本。 AsSpan 也不执行任何堆分配。 |
CA1847:对单个字符查找使用 char 文本 | 搜索单个字符时使用 String.Contains(char) 而不是 String.Contains(string) 。 |
CA1848:使用 LoggerMessage 委托 | 为了提高性能,请使用 LoggerMessage 委托。 |
CA1849:当在异步方法中时,调用异步方法 | 在已属于异步的方法中,对其他方法的调用应指向其存在的异步版本。 |
CA1850:首选静态 HashData 方法,而非 ComputeHash |
相比创建并管理 HashAlgorithm 实例来调用 ComputeHash ,使用静态 HashData 方法更高效。 |
CA1851:可能多次枚举了 IEnumerable 集合 |
可能多次枚举了 IEnumerable 集合。 请考虑使用避免多次枚举的实现。 |
CA1852:密封内部类型 | 在其程序集外部不可访问且其包含程序集中没有子类型的类型不会密封。 |
CA1853:对“Dictionary.ContainsKey(key)”的不必要调用 | 无需使用 Dictionary.ContainsKey(key) 保护 Dictionary.Remove(key) 。 Dictionary<TKey,TValue>.Remove(TKey) 已检查密钥是否存在,如果不存在,则不会引发异常。 |
CA1854:首选“IDictionary.TryGetValue(TKey, out TValue)”方法 | 首选“TryGetValue”而不是受“ContainsKey”检查保护的字典索引器访问。 “ContainsKey”和索引器都查找键,因此使用“TryGetValue”可避免额外的查找。 |
CA1855:使用 Span<T>.Clear() 而不是 Span<T>.Fill() | 若要使用默认值填充某范围的元素,调用 Span<T>.Clear() 比调用 Span<T>.Fill(T) 更高效。 |
CA1856:ConstantExpected 属性的用法不正确 | 未在参数上正确应用 ConstantExpectedAttribute 属性。 |
CA1857:该参数需要一个常量来获得最佳性能。 | 向通过 ConstantExpectedAttribute 注释的参数传递了无效的自变量。 |
CA1858:使用 StartsWith 而不是 IndexOf | 与调用 String.IndexOf 相比,调用 String.StartsWith 检查字符串是否以给定前缀开头更高效。 |
CA1859:尽可能使用具体类型来提高性能 | 代码使用接口类型或抽象类型,导致不必要的接口调用或虚拟调用。 |
CA1860:避免使用“Enumerable.Any()”扩展方法 | 相比调用 Enumerable.Any 来确定集合类型是否具有任何元素,使用 Length 、Count 或 IsEmpty (如果可能)来确定将更有效、更清晰。 |
CA1861:避免将常量数组用作参数 | 不会重复使用作为参数传递的常量数组,这意味着会产生性能开销。 请考虑将它们提取到“静态只读”字段中,以提高性能。 |
CA1862:使用“StringComparison”方法重载执行不区分大小写的字符串比较 | 当代码调用 ToLower() 或 ToUpper() 执行不区分大小写的字符串比较时,将执行不必要的分配。 |
CA1863:使用“CompositeFormat” | 若要降低格式设置成本,请缓存并使用 CompositeFormat 实例作为参数 String.Format 或 StringBuilder.AppendFormat 。 |
CA1864:首选“IDictionary.TryAdd(TKey, TValue)”方法 | Dictionary<TKey,TValue>.ContainsKey(TKey) 和 Dictionary<TKey,TValue>.Add 都执行查找操作,这是冗余设置。 调用 Dictionary<TKey,TValue>.TryAdd 更高效,后者返回 bool ,指示是否添加了值。 如果键已存在,则 TryAdd 不会覆盖该键的值。 |
CA1865-CA1867:使用 char 重载 | 对于单字符串,char 重载的性能更好。 |
CA1868:针对集的对“Contains”不必要调用 | ISet<T>.Add(T) 和 ICollection<T>.Remove(T) 都会执行查找,这使得事先调用 ICollection<T>.Contains(T) 变得多余。 直接调用 Add(T) 或 Remove(T) 更高效,此方法会返回一个布尔值,指示是已添加还是已删除项。 |
CA1869:缓存并重用“JsonSerializerOptions”实例 | 如果你的代码执行多次,则使用 JsonSerializerOptions 的本地实例进行序列化或反序列化可能会大幅降低应用程序的性能,因为 System.Text.Json 会在内部将序列化相关的元数据缓存到提供的实例中。 |
CA1870:使用缓存的“SearchValues”实例 | 与将值直接传递给“IndexOfAny”或“ContainsAny”相比,使用缓存的 SearchValues<T> 更加高效。 |
CA1871:不要将可为 null 的结构传递给“ArgumentNullException.ThrowIfNull” | “ArgumentNullException.ThrowIfNull”接受“object”,因此传递可为 null 的结构可能会导致装箱值。 |
CA1872:首选“Convert.ToHexString”和“Convert.ToHexStringLower”,而不是基于“BitConverter.ToString”的调用链 | 使用 Convert.ToHexString 或 Convert.ToHexStringLower 将字节编码为十六进制字符串表示形式。 与结合使用BitConverter.ToStringString.Replace替换短划线和替换短划线相比,这些方法更加高效和String.ToLower分配友好。 |