diff --git a/docs/fundamentals/code-analysis/quality-rules/ca1846.md b/docs/fundamentals/code-analysis/quality-rules/ca1846.md new file mode 100644 index 0000000000000..ccfaa217214ca --- /dev/null +++ b/docs/fundamentals/code-analysis/quality-rules/ca1846.md @@ -0,0 +1,77 @@ +--- +title: "CA1846: Prefer `AsSpan` over `Substring`" +description: "Learn about code analysis rule CA1846: Prefer `AsSpan` over `Substring`" +ms.date: 05/21/2021 +ms.topic: reference +f1_keywords: +- CA1846 +- PreferAsSpanOverSubstring +helpviewer_keywords: +- PreferAsSpanOverSubstring +- CA1846 +author: NewellClark +dev_langs: +- CSharp +- VB +--- +# CA1846: Prefer `AsSpan` over `Substring` + +| | Value | +|-|-| +| **Rule ID** |CA1846| +| **Category** |[Performance](performance-warnings.md)| +| **Fix is breaking or non-breaking** |Non-breaking| + +## Cause + +The result of a call to one of the <xref:System.String.Substring%2A?displayProperty=nameWithType> overloads is passed to a method with an available overload that accepts `ReadOnlySpan<Char>`. + +## Rule description + +`Substring` allocates a new `string` object on the heap and performs a full copy of the extracted text. String manipulation is a performance bottleneck for many programs. Allocating many small, short-lived strings on a hot path can create enough collection pressure to impact performance. The O(n) copies created by `Substring` become relevant when the substrings get large. The <xref:System.Span%601> and <xref:System.ReadOnlySpan%601> types were created to solve these performance problems. + +Many APIs that accept strings also have overloads that accept a `ReadOnlySpan<System.Char>` argument. When such overloads are available, you can improve performance by calling `AsSpan` instead of `Substring`. + +## How to fix violations + +To fix a violation of this rule, replace the call to `string.Substring` with a call to one of the <xref:System.MemoryExtensions.AsSpan%2A?displayProperty=nameWithType> extension methods. + +```csharp +using System; + +public void MyMethod(string iniFileLine) +{ + // Violation + int.TryParse(iniFileLine.Substring(7), out int x); + int.TryParse(iniFileLine.Substring(2, 5), out int y); + + // Fix + int.TryParse(iniFileLine.AsSpan(7), out int x); + int.TryParse(iniFileLine.AsSpan(2, 5), out int y); +} +``` + +```vb +Imports System + +Public Sub MyMethod(iniFileLine As String) + Dim x As Integer + Dim y As Integer + + ' Violation + Integer.TryParse(iniFileLine.Substring(7), x) + Integer.TryParse(iniFileLine.Substring(2, 5), y) + + ' Fix + Integer.TryParse(iniFileLine.AsSpan(7), x) + Integer.TryParse(iniFileLine.AsSpan(2, 5), y) +End Sub +``` + +## When to suppress warnings + +It is safe to suppress warnings from this rule if performance is not a concern. + +## See also + +- [Performance warnings](performance-warnings.md) diff --git a/docs/fundamentals/code-analysis/quality-rules/index.md b/docs/fundamentals/code-analysis/quality-rules/index.md index 304884b47c730..712b7222784d7 100644 --- a/docs/fundamentals/code-analysis/quality-rules/index.md +++ b/docs/fundamentals/code-analysis/quality-rules/index.md @@ -131,6 +131,7 @@ The following table lists code quality analysis rules. > | [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. | > | [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. | > | [CA1845: Use span-based 'string.Concat'](ca1845.md) | It is more efficient to use `AsSpan` and `string.Concat`, instead of `Substring` and a concatenation operator. | +> | [CA1846: Prefer `AsSpan` over `Substring`](ca1846.md) | `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. | > | [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. | > |[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. | > | [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. | diff --git a/docs/fundamentals/code-analysis/quality-rules/performance-warnings.md b/docs/fundamentals/code-analysis/quality-rules/performance-warnings.md index 9fd26753e6ab0..c6b99ef83dd11 100644 --- a/docs/fundamentals/code-analysis/quality-rules/performance-warnings.md +++ b/docs/fundamentals/code-analysis/quality-rules/performance-warnings.md @@ -51,3 +51,4 @@ Performance rules support high-performance libraries and applications. | [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. | | [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. | | [CA1845: Use span-based 'string.Concat'](ca1845.md) | It is more efficient to use `AsSpan` and `string.Concat`, instead of `Substring` and a concatenation operator. | +| [CA1846: Prefer `AsSpan` over `Substring`](ca1846.md) | `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. | diff --git a/docs/fundamentals/toc.yml b/docs/fundamentals/toc.yml index c526dc191182a..4ad0ec7aa12b3 100644 --- a/docs/fundamentals/toc.yml +++ b/docs/fundamentals/toc.yml @@ -884,6 +884,8 @@ items: href: code-analysis/quality-rules/ca1841.md - name: CA1845 href: code-analysis/quality-rules/ca1845.md + - name: CA1846 + href: code-analysis/quality-rules/ca1846.md - name: SingleFile rules items: - name: Overview