From 496092a6d8a512610f65316843f1a6eddd586660 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 27 Oct 2025 11:27:34 -0400 Subject: [PATCH 1/7] Create stub for CS9229 Create the stub article, and add the information for CS9229. --- .../using-statement-declaration-errors.md | 30 +++++++++++++++++++ docs/csharp/language-reference/toc.yml | 4 +++ ...n-t-have-specifics-on-this-csharp-error.md | 2 -- 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md diff --git a/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md b/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md new file mode 100644 index 0000000000000..6141a03549a46 --- /dev/null +++ b/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md @@ -0,0 +1,30 @@ +--- +title: Resolve errors related to `using` statements and `using` declarations. +description: These errors indicate an incorrect use of the `using` statement or `using` declarations. Learn about the errors and how to fix them. +f1_keywords: + - "CS9229" +helpviewer_keywords: + - "CS9229" +ms.date: 10/27/2025 +ai-usage: ai-assisted +--- +# Resolve warnings related to the `using` statements and `using` declarations + +This article covers the following compiler errors: + + +- [**CS9229**](#incorrect-using-declaration): *Modifiers cannot be placed on using declarations.* + +## Incorrect `using` declaration + +- **CS9229**: *Modifiers cannot be placed on using declarations.* + +A variable declaration wrapped in a `using` declaration can't include any of the following modifiers: + +- `const` +- `static` +- `volatile` +- `readonly` +- Acccessibility modifiers: `public`, `protected`, `internal`, `private`, `protected internal` or `private protected` diff --git a/docs/csharp/language-reference/toc.yml b/docs/csharp/language-reference/toc.yml index 8a866c5b23fe1..d494c7c7e0687 100644 --- a/docs/csharp/language-reference/toc.yml +++ b/docs/csharp/language-reference/toc.yml @@ -604,6 +604,10 @@ items: CS0105, CS0138, CS0431, CS0432, CS0440, CS0576, CS0687, CS1529, CS1537, CS7000, CS7007, CS8019, CS8083, CS8085, CS8914, CS8915, CS8933, CS9055, CS9130, CS9131, CS9132, CS9133, CS9162, CS9163 + - name: Using statements and declarations + href: ./compiler-messages/using-statement-declaration-errors.md + displayName: > + CS9229 - name: Source generators href: ./compiler-messages/source-generator-errors.md displayName: > diff --git a/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md b/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md index 0e67559e90914..933a0d019d031 100644 --- a/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md +++ b/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md @@ -552,8 +552,6 @@ f1_keywords: - "CS9095" - "CS9096" - "CS9097" -# C# 12 errors begin here - - "CS9229" # Modifiers cannot be placed on using declarations (using declarations) # C# 14 errors begin here - "CS9327" - "CS9328" From 21e57572379286cde0be90a4fea2850b0ebb69e1 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 27 Oct 2025 11:33:38 -0400 Subject: [PATCH 2/7] update all instructions for this task Make more prompt edits to make future changes easier. --- .github/prompts/error-consolidation.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/prompts/error-consolidation.md b/.github/prompts/error-consolidation.md index 4d96290538393..0b3244152a8f1 100644 --- a/.github/prompts/error-consolidation.md +++ b/.github/prompts/error-consolidation.md @@ -10,9 +10,12 @@ Overall steps: ## Add a single existing file into the new consolidated article. -We're going to work through a series of files consolidating errors and warnings related to declaring the `dynamic` type and dynamic binding. +We're going to work through a series of files consolidating errors and warnings. -The destination for all these edits is the dynamic-type-and-binding-errors.md file. It already contains a skeleton for the final output. +- For the duration of this chat, all references to "destination file" refer to `using-statement-declaration-errors.md. +- For the duration of this chat, all references to "the target theme" refer to errors and warnings related to `using` statements and `using` variable declarations. Note that the `using` keyword can also be used for a `using` directive. Don't include those error messages. + +The destination file already contains a skeleton for the final output. For each source file I specify in this chat, you'll do the following tasks: @@ -28,7 +31,7 @@ For each source file I specify in this chat, you'll do the following tasks: ## Search for other related articles that may be missed. -Search all files in the docs/csharp/language-reference/compiler-messages and the docs/csharp/misc folder for any other errors and warnings that involve the `dynamic` type or dynamic binding. Give me a list to review for possible additional consolidation. Don't make any edits until the originating user approves. +Search all files in the docs/csharp/language-reference/compiler-messages and the docs/csharp/misc folder for any other errors and warnings that involve the target theme. Give me a list to review for possible additional consolidation. Don't make any edits until the originating user approves. ## Final search in roslyn source @@ -36,22 +39,22 @@ Let's check undocumented errors and the roslyn source for any missing errors. F 1. Find that number as a constant in `ErrorCodes.cs`. 2. Locate the corresponding `data` element in CSharpResources.resx. The `name` atttribute should match the number of the constant. 3. Read the error message found in the `` element that is a child of that `` element. -Give me a list of all error numbers and corresponding error messages that relate to operator overloading. +Give me a list of all error numbers and corresponding error messages that relate to the target theme. -To make sure you've found all related errors, we'll check the source. Look in `CSharpResources.resx` for any elements where the `` element is a message related to preprocessor tokens. The symbolic constant for that value is in the `name` attribute on the parent `data` element. Find that value in `ErrorCodes.cs`. It will map to the compiler error code, where the code is "CS" followed by the number as a four digit number. Build a list of any related errors, but don't make any edits yet. +To make sure you've found all related errors, we'll check the source. Look in `CSharpResources.resx` for any elements where the `` element is a message related to the target theme. The symbolic constant for that value is in the `name` attribute on the parent `data` element. Find that value in `ErrorCodes.cs`. It will map to the compiler error code, where the code is "CS" followed by the number as a four digit number. Build a list of any related errors, but don't make any edits yet. I'll give you error codes one by one. For each, I want you to do the following: -- Add the new error code to the front matter of operator-overloading-errors.md, for both the `f1_keywords` and `helpview_keywords` table. -- Add the new error code and error message to the table at the top of operator-overloading-errors.md. -- Add the new error code to the list of `displayName` elements in the TOC file for operator-overloading-errors.md. +- Add the new error code to the front matter of the destination file, for both the `f1_keywords` and `helpview_keywords` table. +- Add the new error code and error message to the table at the top of the destination file. +- Add the new error code to the list of `displayName` elements in the TOC file entry for the destination file. - Remove the new error code from the front matter in the file `csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-errors.md` file. Note that no redirections need to be added for these error codes. ## Build consolidated sections -For all remaining work, all edits will be in the `dynamic-type-and-binding-errors.md` file. The final format should mirror the structure of the `preprocessor-errors.md` file. Every H2 is a theme, all anchors are for the theme, not an individual error code. +For all remaining work, all edits will be in the target file. The final format should mirror the structure of the other target theme files in the docs/csharp/language-reference/compiler-messages folder. Every H2 is a theme, all anchors are for the theme, not an individual error code. To do that, make a new H2 section for the theme. Remove all the H2s for the individual error codes that are part of that theme. Where applicable, the new H2 can include text or examples from the H2s you remove. The new section should include links to language reference articles that discuss the feature or theme. From e77479e68162cfd4d6850afa1d3444f4b8fa626e Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 27 Oct 2025 14:17:20 -0400 Subject: [PATCH 3/7] Add using statement errors That's the original theme. --- .openpublishing.redirection.csharp.json | 28 ++ .../compiler-messages/cs1674.md | 77 ----- .../compiler-messages/cs8410.md | 44 --- .../using-statement-declaration-errors.md | 310 ++++++++++++++++++ docs/csharp/language-reference/toc.yml | 6 +- ...n-t-have-specifics-on-this-csharp-error.md | 5 - 6 files changed, 339 insertions(+), 131 deletions(-) delete mode 100644 docs/csharp/language-reference/compiler-messages/cs1674.md delete mode 100644 docs/csharp/language-reference/compiler-messages/cs8410.md diff --git a/.openpublishing.redirection.csharp.json b/.openpublishing.redirection.csharp.json index abe2661b9fba2..f923bdb914915 100644 --- a/.openpublishing.redirection.csharp.json +++ b/.openpublishing.redirection.csharp.json @@ -563,6 +563,30 @@ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs8401.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/feature-version-errors" }, + { + "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs8410.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#type-must-be-async-disposable" + }, + { + "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs8417.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#async-disposable-type-used-with-using" + }, + { + "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs8418.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#disposable-type-used-with-await-using" + }, + { + "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs8647.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#using-variable-in-switch-section" + }, + { + "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs8648.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#goto-forward-jump-over-using-declaration" + }, + { + "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs8649.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#goto-backward-jump-over-using-declaration" + }, { "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs8795.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/partial-types" @@ -2285,6 +2309,10 @@ "source_path_from_root": "/docs/csharp/misc/cs1673.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/lambda-expression-errors#syntax-limitations-in-lambda-expressions" }, + { + "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1674.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#type-must-be-disposable" + }, { "source_path_from_root": "/docs/csharp/misc/cs1686.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/lambda-expression-errors#syntax-limitations-in-lambda-expressions" diff --git a/docs/csharp/language-reference/compiler-messages/cs1674.md b/docs/csharp/language-reference/compiler-messages/cs1674.md deleted file mode 100644 index 50e0ac69d347b..0000000000000 --- a/docs/csharp/language-reference/compiler-messages/cs1674.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -description: "Compiler Error CS1674" -title: "Compiler Error CS1674" -ms.date: 07/20/2015 -f1_keywords: - - "CS1674" -helpviewer_keywords: - - "CS1674" -ms.assetid: 7a018629-35f4-406a-8a5f-1cee7343da6d ---- -# Compiler Error CS1674 - -'T': type used in a using statement must be implicitly convertible to 'System.IDisposable' - - The [using statement](../statements/using.md) is intended to be used to ensure the disposal of an object at the end of the `using` block, thus, only types which are disposable may be used in such a statement. For example, value types are not disposable, and type parameters which are not constrained to be classes may not be assumed to be disposable. - -## Example 1 - - The following sample generates CS1674. - -```csharp -// CS1674.cs -class C -{ - public static void Main() - { - int a = 0; - a++; - - using (a) {} // CS1674 - } -} -``` - -## Example 2 - - The following sample generates CS1674. - -```csharp -// CS1674_b.cs -using System; -class C { - public void Test() { - using (C c = new C()) {} // CS1674 - } -} - -// OK -class D : IDisposable { - void IDisposable.Dispose() {} - public void Dispose() {} - - public static void Main() { - using (D d = new D()) {} - } -} -``` - -## Example 3 - - The following case illustrates the need for a class type constraint to guarantee that an unknown type parameter is disposable. The following sample generates CS1674. - -```csharp -// CS1674_c.cs -// compile with: /target:library -using System; -public class C -// Add a class type constraint that specifies a disposable class. -// Uncomment the following line to resolve. -// public class C where T : IDisposable -{ - public void F(T t) - { - using (t) {} // CS1674 - } -} -``` diff --git a/docs/csharp/language-reference/compiler-messages/cs8410.md b/docs/csharp/language-reference/compiler-messages/cs8410.md deleted file mode 100644 index 781c229fdaaa4..0000000000000 --- a/docs/csharp/language-reference/compiler-messages/cs8410.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -description: "Learn more about: Compiler Error CS8410" -title: Compiler Error CS8410 -ms.date: 07/11/2020 -f1_keywords: - - "CS8410" -helpviewer_keywords: - - "CS8410" -author: Youssef1313 ---- -# Compiler Error CS8410 - -'type': type used in an asynchronous `using` statement must be implicitly convertible to 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. - -The expression inside an `await using` statement must have a `DisposeAsync` method. - -## To correct this error - -Remove the `await using` keywords, or implement a suitable `DisposeAsync` method. - -## Example - -```csharp -using System.Threading.Tasks; - -class Program -{ - static async Task Main() - { - // error CS8410: 'Example': type used in an asynchronous using statement - // must be implicitly convertible to 'System.IAsyncDisposable' or implement - // a suitable 'DisposeAsync' method. - await using var example = new Example(); - } -} - -class Example -{ -} -``` - -## See also - -- [Implement a DisposeAsync method](../../../standard/garbage-collection/implementing-disposeasync.md) diff --git a/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md b/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md index 6141a03549a46..576d969dbedc8 100644 --- a/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md +++ b/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md @@ -2,8 +2,22 @@ title: Resolve errors related to `using` statements and `using` declarations. description: These errors indicate an incorrect use of the `using` statement or `using` declarations. Learn about the errors and how to fix them. f1_keywords: + - "CS1674" + - "CS8410" + - "CS8417" + - "CS8418" + - "CS8647" + - "CS8648" + - "CS8649" - "CS9229" helpviewer_keywords: + - "CS1674" + - "CS8410" + - "CS8417" + - "CS8418" + - "CS8647" + - "CS8648" + - "CS8649" - "CS9229" ms.date: 10/27/2025 ai-usage: ai-assisted @@ -15,8 +29,304 @@ This article covers the following compiler errors: +- [**CS1674**](#type-must-be-disposable): *'T': type used in a using statement must be implicitly convertible to 'System.IDisposable'* +- [**CS8410**](#type-must-be-async-disposable): *'type': type used in an asynchronous `using` statement must be implicitly convertible to 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method.* +- [**CS8417**](#async-disposable-type-used-with-using): *'type': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'?* +- [**CS8418**](#disposable-type-used-with-await-using): *'type': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'?* +- [**CS8647**](#using-variable-in-switch-section): *A using variable cannot be used directly within a switch section (consider using braces).* +- [**CS8648**](#goto-forward-jump-over-using-declaration): *A goto cannot jump to a location after a using declaration.* +- [**CS8649**](#goto-backward-jump-over-using-declaration): *A goto cannot jump to a location before a using declaration within the same block.* - [**CS9229**](#incorrect-using-declaration): *Modifiers cannot be placed on using declarations.* +## Type must be disposable + +- **CS1674**: *'T': type used in a using statement must be implicitly convertible to 'System.IDisposable'* + +The [using statement](../statements/using.md) ensures the disposal of an object at the end of the `using` block. Only types that are disposable can be used in such a statement. For example, value types aren't disposable, and type parameters that aren't constrained to be classes can't be assumed to be disposable. + +The following sample generates CS1674: + +```csharp +// CS1674.cs +class C +{ + public static void Main() + { + int a = 0; + a++; + + using (a) {} // CS1674 + } +} +``` + +The following sample generates CS1674: + +```csharp +// CS1674_b.cs +using System; +class C { + public void Test() { + using (C c = new C()) {} // CS1674 + } +} + +// OK +class D : IDisposable { + void IDisposable.Dispose() {} + public void Dispose() {} + + public static void Main() { + using (D d = new D()) {} + } +} +``` + +The following case illustrates the need for a class type constraint to guarantee that an unknown type parameter is disposable. The following sample generates CS1674: + +```csharp +// CS1674_c.cs +// compile with: /target:library +using System; +public class C +// Add a class type constraint that specifies a disposable class. +// Uncomment the following line to resolve. +// public class C where T : IDisposable +{ + public void F(T t) + { + using (t) {} // CS1674 + } +} +``` + +## Type must be async disposable + +- **CS8410**: *'type': type used in an asynchronous `using` statement must be implicitly convertible to 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method.* + +The expression inside an `await using` statement must have a `DisposeAsync` method. + +To correct this error, remove the `await using` keywords, or implement a suitable `DisposeAsync` method. + +The following example generates CS8410: + +```csharp +using System.Threading.Tasks; + +class Program +{ + static async Task Main() + { + // error CS8410: 'Example': type used in an asynchronous using statement + // must be implicitly convertible to 'System.IAsyncDisposable' or implement + // a suitable 'DisposeAsync' method. + await using var example = new Example(); + } +} + +class Example +{ +} +``` + +For more information, see [Implement a DisposeAsync method](../../../standard/garbage-collection/implementing-disposeasync.md). + +## Async disposable type used with `using` + +- **CS8417**: *'type': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'?* + +You used `await using` with a type that implements but not . The compiler suggests you might have meant to use a synchronous `using` statement instead. + +The following example generates CS8417: + +```csharp +using System; +using System.Threading.Tasks; + +class Program +{ + static async Task Main() + { + // error CS8417: 'Example': type used in an asynchronous using statement + // must implement 'System.IAsyncDisposable' or implement a suitable + // 'DisposeAsync' method. Did you mean 'using' rather than 'await using'? + await using var example = new Example(); + } +} + +class Example : IDisposable +{ + public void Dispose() { } +} +``` + +To correct this error, either: +- Change `await using` to `using` if synchronous disposal is appropriate +- Implement if asynchronous disposal is needed + +For more information, see [Implement a DisposeAsync method](../../../standard/garbage-collection/implementing-disposeasync.md). + +## Disposable type used with `await using` + +- **CS8418**: *'type': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'?* + +You used a synchronous `using` statement with a type that implements but not . The compiler suggests you might have meant to use `await using` instead. + +The following example generates CS8418: + +```csharp +using System; +using System.Threading.Tasks; + +class Program +{ + static async Task Main() + { + // error CS8418: 'Example': type used in a using statement must implement + // 'System.IDisposable'. Did you mean 'await using' rather than 'using'? + using var example = new Example(); + } +} + +class Example : IAsyncDisposable +{ + public ValueTask DisposeAsync() => ValueTask.CompletedTask; +} +``` + +To correct this error, either: +- Change `using` to `await using` if asynchronous disposal is appropriate +- Implement if synchronous disposal is needed + +For more information, see [Implement a DisposeAsync method](../../../standard/garbage-collection/implementing-disposeasync.md). + +## Using variable in switch section + +- **CS8647**: *A using variable cannot be used directly within a switch section (consider using braces).* + +A `using` declaration creates a variable that is disposed at the end of its scope. When used directly in a switch section without braces, the scope is ambiguous and can lead to errors. + +The following example generates CS8647: + +```csharp +using System; + +class Program +{ + static void Main() + { + int choice = 1; + switch (choice) + { + case 1: + // error CS8647: A using variable cannot be used directly within + // a switch section (consider using braces). + using var resource = new Resource(); + Console.WriteLine("Case 1"); + break; + } + } +} + +class Resource : IDisposable +{ + public void Dispose() { } +} +``` + +To correct this error, wrap the switch section content in braces: + +```csharp +switch (choice) +{ + case 1: + { + using var resource = new Resource(); + Console.WriteLine("Case 1"); + break; + } +} +``` + +For more information, see [using statement](../statements/using.md). + +## Goto forward jump over using declaration + +- **CS8648**: *A goto cannot jump to a location after a using declaration.* + +You cannot use a `goto` statement to jump forward over a `using` declaration. The `using` declaration creates a resource that must be properly disposed, and jumping over it would skip the resource initialization. + +The following example generates CS8648: + +```csharp +using System; + +class Program +{ + static void Main() + { + goto label; + + // error CS8648: A goto cannot jump to a location after a using declaration. + using var resource = new Resource(); + + label: + Console.WriteLine("After label"); + } +} + +class Resource : IDisposable +{ + public void Dispose() { } +} +``` + +To correct this error, restructure your code to avoid jumping over the `using` declaration. You can: +- Move the `using` declaration before the label +- Remove the `goto` statement and use structured control flow +- Place the `using` declaration in a separate scope + +For more information, see [using statement](../statements/using.md). + +## Goto backward jump over using declaration + +- **CS8649**: *A goto cannot jump to a location before a using declaration within the same block.* + +You cannot use a `goto` statement to jump backward to a location before a `using` declaration within the same block. This would create a control flow that could skip proper disposal of the resource. + +The following example generates CS8649: + +```csharp +using System; + +class Program +{ + static void Main() + { + label: + Console.WriteLine("At label"); + + using var resource = new Resource(); + + // error CS8649: A goto cannot jump to a location before a using + // declaration within the same block. + goto label; + } +} + +class Resource : IDisposable +{ + public void Dispose() { } +} +``` + +To correct this error, restructure your code to avoid jumping backward over the `using` declaration. You can: +- Remove the `goto` statement and use structured control flow like loops +- Place the `using` declaration in a separate scope outside the jump target +- Restructure the logic to avoid the backward jump + +For more information, see [using statement](../statements/using.md). + ## Incorrect `using` declaration - **CS9229**: *Modifiers cannot be placed on using declarations.* diff --git a/docs/csharp/language-reference/toc.yml b/docs/csharp/language-reference/toc.yml index d494c7c7e0687..3bf96edc08574 100644 --- a/docs/csharp/language-reference/toc.yml +++ b/docs/csharp/language-reference/toc.yml @@ -607,7 +607,7 @@ items: - name: Using statements and declarations href: ./compiler-messages/using-statement-declaration-errors.md displayName: > - CS9229 + CS1674, CS8410, CS8417, CS8418, CS8647, CS8648, CS8649, CS9229 - name: Source generators href: ./compiler-messages/source-generator-errors.md displayName: > @@ -1635,8 +1635,6 @@ items: href: ../misc/cs1671.md - name: CS1672 href: ../misc/cs1672.md - - name: CS1674 - href: ./compiler-messages/cs1674.md - name: CS1675 href: ../misc/cs1675.md - name: CS1676 @@ -1911,8 +1909,6 @@ items: href: ./compiler-messages/cs8355.md - name: CS8403 href: ./compiler-messages/cs8403.md - - name: CS8410 - href: ./compiler-messages/cs8410.md - name: CS8411 href: ./compiler-messages/cs8411.md - name: CS8422 diff --git a/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md b/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md index 933a0d019d031..e33a9a15c0a6d 100644 --- a/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md +++ b/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md @@ -302,8 +302,6 @@ f1_keywords: - "CS8413" - "CS8414" - "CS8415" - - "CS8417" - - "CS8418" - "CS8419" - "CS8420" - "CS8421" @@ -335,9 +333,6 @@ f1_keywords: - "CS8635" - "CS8641" - "CS8646" - - "CS8647" - - "CS8648" - - "CS8649" - "CS8650" - "CS8651" - "CS8656" From ce0ca2954dcc1e65e1673e5bba9465550cec3bb8 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 27 Oct 2025 14:51:00 -0400 Subject: [PATCH 4/7] Finish any remaining consolidation --- .openpublishing.redirection.csharp.json | 8 ++ .../using-statement-declaration-errors.md | 100 ++++++++++++++++++ docs/csharp/language-reference/toc.yml | 2 +- docs/csharp/misc/cs0245.md | 43 -------- docs/csharp/misc/cs0728.md | 69 ------------ 5 files changed, 109 insertions(+), 113 deletions(-) delete mode 100644 docs/csharp/misc/cs0245.md delete mode 100644 docs/csharp/misc/cs0728.md diff --git a/.openpublishing.redirection.csharp.json b/.openpublishing.redirection.csharp.json index f923bdb914915..fd8d3d1af25de 100644 --- a/.openpublishing.redirection.csharp.json +++ b/.openpublishing.redirection.csharp.json @@ -1713,6 +1713,10 @@ "source_path_from_root": "/docs/csharp/misc/cs0244.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/unsafe-code-errors" }, + { + "source_path_from_root": "/docs/csharp/misc/cs0245.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#cannot-call-finalize-directly" + }, { "source_path_from_root": "/docs/csharp/misc/cs0254.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/unsafe-code-errors" @@ -1889,6 +1893,10 @@ "source_path_from_root": "/docs/csharp/misc/cs0715.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors" }, + { + "source_path_from_root": "/docs/csharp/misc/cs0728.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#assignment-to-using-variable" + }, { "source_path_from_root": "/docs/csharp/misc/cs1037.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors" diff --git a/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md b/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md index 576d969dbedc8..a9dad42f2ae5b 100644 --- a/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md +++ b/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md @@ -2,6 +2,8 @@ title: Resolve errors related to `using` statements and `using` declarations. description: These errors indicate an incorrect use of the `using` statement or `using` declarations. Learn about the errors and how to fix them. f1_keywords: + - "CS0245" + - "CS0728" - "CS1674" - "CS8410" - "CS8417" @@ -11,6 +13,8 @@ f1_keywords: - "CS8649" - "CS9229" helpviewer_keywords: + - "CS0245" + - "CS0728" - "CS1674" - "CS8410" - "CS8417" @@ -29,6 +33,8 @@ This article covers the following compiler errors: +- [**CS0245**](#cannot-call-finalize-directly): *Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available.* +- [**CS0728**](#assignment-to-using-variable): *Possibly incorrect assignment to local 'variable' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.* - [**CS1674**](#type-must-be-disposable): *'T': type used in a using statement must be implicitly convertible to 'System.IDisposable'* - [**CS8410**](#type-must-be-async-disposable): *'type': type used in an asynchronous `using` statement must be implicitly convertible to 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method.* - [**CS8417**](#async-disposable-type-used-with-using): *'type': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'?* @@ -38,6 +44,100 @@ That's be design. The text closely matches the text of the compiler error / warn - [**CS8649**](#goto-backward-jump-over-using-declaration): *A goto cannot jump to a location before a using declaration within the same block.* - [**CS9229**](#incorrect-using-declaration): *Modifiers cannot be placed on using declarations.* +## Cannot call Finalize directly + +- **CS0245**: *Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available.* + +You cannot directly call a destructor (finalizer) or the method. The garbage collector automatically calls finalizers when an object is no longer referenced. If you need deterministic cleanup, implement the interface and call the `Dispose` method. + +The following example generates CS0245: + +```csharp +using System; + +class MyClass +{ + void Method() + { + this.Finalize(); // CS0245: cannot call Finalize directly + } + + public static void Main() { } +} +``` + +To correct this error, implement and call `Dispose`: + +```csharp +using System; + +class MyClass : IDisposable +{ + public void Dispose() + { + // Cleanup code goes here + GC.SuppressFinalize(this); + } + + void Method() + { + this.Dispose(); // Correct: call Dispose instead + } + + public static void Main() { } +} +``` + +For more information, see [Finalizers](../../programming-guide/classes-and-structs/finalizers.md) and [Implement a Dispose method](../../../standard/garbage-collection/implementing-dispose.md). + +## Assignment to using variable + +- **CS0728**: *Possibly incorrect assignment to local 'variable' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.* + +This warning indicates that you assigned a new value to a variable that is the resource in a `using` statement. The dispose call will occur on the original value, not the newly assigned value, which can lead to resource leaks. + +The following example generates CS0728: + +```csharp +using System; + +public class ValidBase : IDisposable +{ + public void Dispose() { } +} + +public class Program +{ + public static void Main() + { + ValidBase vb = null; + using (vb) + { + vb = new ValidBase(); // CS0728: assignment to using variable + } + // The Dispose call happens on null, not on the newly created ValidBase object + } +} +``` + +To correct this error, initialize the resource in the `using` statement declaration: + +```csharp +using (ValidBase vb = new ValidBase()) +{ + // Use vb +} +``` + +Or with a `using` declaration: + +```csharp +using ValidBase vb = new ValidBase(); +// Use vb +``` + +For more information, see [using statement](../statements/using.md). + ## Type must be disposable - **CS1674**: *'T': type used in a using statement must be implicitly convertible to 'System.IDisposable'* diff --git a/docs/csharp/language-reference/toc.yml b/docs/csharp/language-reference/toc.yml index 3bf96edc08574..af8606c9862e8 100644 --- a/docs/csharp/language-reference/toc.yml +++ b/docs/csharp/language-reference/toc.yml @@ -607,7 +607,7 @@ items: - name: Using statements and declarations href: ./compiler-messages/using-statement-declaration-errors.md displayName: > - CS1674, CS8410, CS8417, CS8418, CS8647, CS8648, CS8649, CS9229 + CS0245, CS0728, CS1674, CS8410, CS8417, CS8418, CS8647, CS8648, CS8649, CS9229 - name: Source generators href: ./compiler-messages/source-generator-errors.md displayName: > diff --git a/docs/csharp/misc/cs0245.md b/docs/csharp/misc/cs0245.md deleted file mode 100644 index 3881c1aeb9d3f..0000000000000 --- a/docs/csharp/misc/cs0245.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -description: "Compiler Error CS0245" -title: "Compiler Error CS0245" -ms.date: 07/20/2015 -f1_keywords: - - "CS0245" -helpviewer_keywords: - - "CS0245" -ms.assetid: 3f2beb2f-a510-4568-9d11-bb1f65066acd ---- -# Compiler Error CS0245 - -Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available. - - For more information, see [Programming Essentials for Garbage Collection](../../standard/garbage-collection/index.md) and [Finalizers](../programming-guide/classes-and-structs/finalizers.md). - - The following sample generates CS0245: - -```csharp -// CS0245.cs -using System; -using System.Collections; - -class MyClass // : IDisposable -{ - /* - public void Dispose() - { - // cleanup code goes here - } - */ - - void m() - { - this.Finalize(); // CS0245 - // this.Dispose(); - } - - public static void Main() - { - } -} -``` diff --git a/docs/csharp/misc/cs0728.md b/docs/csharp/misc/cs0728.md deleted file mode 100644 index 460d33cca7ecd..0000000000000 --- a/docs/csharp/misc/cs0728.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -description: "Compiler Warning (level 2) CS0728" -title: "Compiler Warning (level 2) CS0728" -ms.date: 07/20/2015 -f1_keywords: - - "CS0728" -helpviewer_keywords: - - "CS0728" -ms.assetid: ad6d860d-bac4-48f3-9eab-1efd2b6de6c0 ---- -# Compiler Warning (level 2) CS0728 - -Possibly incorrect assignment to local 'variable' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local. - - There are several scenarios where `using` or `lock` blocks will result in a temporary leak of resources. Here is one example: - - `thisType f = null;` - - `using (f)` - - `{` - - `f = new thisType();` - - `...` - - `}` - - In this case, the original value, such as null, of the variable `thisType` will be disposed of when the `using` block finishes executing, but the `thisType` object created inside the block will not be, although it will eventually get garbage collected. - - To resolve this error, use the following form: - - `using (thisType f = new thisType())` - - `{` - - `...` - - `}` - - In this case, the newly allocated `thisType` object will be disposed of. - -## Example - - The following code will generate warning CS0728. - -```csharp -// CS0728.cs - -using System; -public class ValidBase : IDisposable -{ - public void Dispose() { } -} - -public class Logger -{ - public static void dummy() - { - ValidBase vb = null; - using (vb) - { - vb = null; // CS0728 - } - vb = null; - } - public static void Main() { } -} -``` From 7e5777d41d3f677eafbec41f34794b7f14cd9335 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 27 Oct 2025 15:07:26 -0400 Subject: [PATCH 5/7] copilot's first pass. Not really thrilled. --- .../using-statement-declaration-errors.md | 268 +++++++++--------- 1 file changed, 135 insertions(+), 133 deletions(-) diff --git a/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md b/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md index a9dad42f2ae5b..f3dbbb7d1c255 100644 --- a/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md +++ b/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md @@ -33,20 +33,30 @@ This article covers the following compiler errors: -- [**CS0245**](#cannot-call-finalize-directly): *Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available.* -- [**CS0728**](#assignment-to-using-variable): *Possibly incorrect assignment to local 'variable' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.* -- [**CS1674**](#type-must-be-disposable): *'T': type used in a using statement must be implicitly convertible to 'System.IDisposable'* -- [**CS8410**](#type-must-be-async-disposable): *'type': type used in an asynchronous `using` statement must be implicitly convertible to 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method.* -- [**CS8417**](#async-disposable-type-used-with-using): *'type': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'?* -- [**CS8418**](#disposable-type-used-with-await-using): *'type': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'?* -- [**CS8647**](#using-variable-in-switch-section): *A using variable cannot be used directly within a switch section (consider using braces).* -- [**CS8648**](#goto-forward-jump-over-using-declaration): *A goto cannot jump to a location after a using declaration.* -- [**CS8649**](#goto-backward-jump-over-using-declaration): *A goto cannot jump to a location before a using declaration within the same block.* +- [**CS0245**](#implementing-idisposable-and-iasyncdisposable): *Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available.* +- [**CS0728**](#using-variable-scope-and-control-flow): *Possibly incorrect assignment to local 'variable' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.* +- [**CS1674**](#implementing-idisposable-and-iasyncdisposable): *'T': type used in a using statement must be implicitly convertible to 'System.IDisposable'* +- [**CS8410**](#implementing-idisposable-and-iasyncdisposable): *'type': type used in an asynchronous `using` statement must be implicitly convertible to 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method.* +- [**CS8417**](#implementing-idisposable-and-iasyncdisposable): *'type': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'?* +- [**CS8418**](#implementing-idisposable-and-iasyncdisposable): *'type': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'?* +- [**CS8647**](#using-variable-scope-and-control-flow): *A using variable cannot be used directly within a switch section (consider using braces).* +- [**CS8648**](#using-variable-scope-and-control-flow): *A goto cannot jump to a location after a using declaration.* +- [**CS8649**](#using-variable-scope-and-control-flow): *A goto cannot jump to a location before a using declaration within the same block.* - [**CS9229**](#incorrect-using-declaration): *Modifiers cannot be placed on using declarations.* -## Cannot call Finalize directly +## Implementing IDisposable and IAsyncDisposable + +The following compiler errors and warnings indicate issues with implementing or using the dispose pattern: - **CS0245**: *Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available.* +- **CS1674**: *'T': type used in a using statement must be implicitly convertible to 'System.IDisposable'* +- **CS8410**: *'type': type used in an asynchronous `using` statement must be implicitly convertible to 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method.* +- **CS8417**: *'type': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'?* +- **CS8418**: *'type': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'?* + +The [using statement](../statements/using.md) ensures proper disposal of resources at the end of the `using` block. To use a type with a `using` statement, it must implement the appropriate disposal interface. For synchronous `using` statements, the type must implement . For asynchronous `await using` statements, the type must implement . + +### Cannot call Finalize directly (CS0245) You cannot directly call a destructor (finalizer) or the method. The garbage collector automatically calls finalizers when an object is no longer referenced. If you need deterministic cleanup, implement the interface and call the `Dispose` method. @@ -88,90 +98,36 @@ class MyClass : IDisposable } ``` -For more information, see [Finalizers](../../programming-guide/classes-and-structs/finalizers.md) and [Implement a Dispose method](../../../standard/garbage-collection/implementing-dispose.md). - -## Assignment to using variable - -- **CS0728**: *Possibly incorrect assignment to local 'variable' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.* - -This warning indicates that you assigned a new value to a variable that is the resource in a `using` statement. The dispose call will occur on the original value, not the newly assigned value, which can lead to resource leaks. - -The following example generates CS0728: - -```csharp -using System; - -public class ValidBase : IDisposable -{ - public void Dispose() { } -} - -public class Program -{ - public static void Main() - { - ValidBase vb = null; - using (vb) - { - vb = new ValidBase(); // CS0728: assignment to using variable - } - // The Dispose call happens on null, not on the newly created ValidBase object - } -} -``` - -To correct this error, initialize the resource in the `using` statement declaration: - -```csharp -using (ValidBase vb = new ValidBase()) -{ - // Use vb -} -``` - -Or with a `using` declaration: +### Type must implement IDisposable (CS1674) -```csharp -using ValidBase vb = new ValidBase(); -// Use vb -``` - -For more information, see [using statement](../statements/using.md). - -## Type must be disposable - -- **CS1674**: *'T': type used in a using statement must be implicitly convertible to 'System.IDisposable'* - -The [using statement](../statements/using.md) ensures the disposal of an object at the end of the `using` block. Only types that are disposable can be used in such a statement. For example, value types aren't disposable, and type parameters that aren't constrained to be classes can't be assumed to be disposable. +Only types that are disposable can be used in a `using` statement. For example, value types aren't disposable, and type parameters that aren't constrained to be classes can't be assumed to be disposable. The following sample generates CS1674: ```csharp -// CS1674.cs class C { public static void Main() { int a = 0; a++; - - using (a) {} // CS1674 + using (a) {} // CS1674: int doesn't implement IDisposable } } ``` -The following sample generates CS1674: +The following sample also generates CS1674: ```csharp -// CS1674_b.cs using System; + class C { public void Test() { - using (C c = new C()) {} // CS1674 + using (C c = new C()) {} // CS1674: C doesn't implement IDisposable } } -// OK +// OK - implements IDisposable class D : IDisposable { void IDisposable.Dispose() {} public void Dispose() {} @@ -185,9 +141,8 @@ class D : IDisposable { The following case illustrates the need for a class type constraint to guarantee that an unknown type parameter is disposable. The following sample generates CS1674: ```csharp -// CS1674_c.cs -// compile with: /target:library using System; + public class C // Add a class type constraint that specifies a disposable class. // Uncomment the following line to resolve. @@ -195,18 +150,14 @@ public class C { public void F(T t) { - using (t) {} // CS1674 + using (t) {} // CS1674: T might not implement IDisposable } } ``` -## Type must be async disposable - -- **CS8410**: *'type': type used in an asynchronous `using` statement must be implicitly convertible to 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method.* - -The expression inside an `await using` statement must have a `DisposeAsync` method. +### Type must implement IAsyncDisposable (CS8410) -To correct this error, remove the `await using` keywords, or implement a suitable `DisposeAsync` method. +The expression inside an `await using` statement must have a `DisposeAsync` method. Types used with `await using` must implement or provide a suitable `DisposeAsync` method. The following example generates CS8410: @@ -229,13 +180,11 @@ class Example } ``` -For more information, see [Implement a DisposeAsync method](../../../standard/garbage-collection/implementing-disposeasync.md). - -## Async disposable type used with `using` +To correct this error, remove the `await using` keywords, or implement a suitable `DisposeAsync` method. -- **CS8417**: *'type': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'?* +### Mismatched disposal pattern (CS8417, CS8418) -You used `await using` with a type that implements but not . The compiler suggests you might have meant to use a synchronous `using` statement instead. +These errors occur when you use the wrong disposal keyword for a type. CS8417 occurs when you use `await using` with a type that only implements (not ). CS8418 occurs when you use synchronous `using` with a type that only implements (not ). The following example generates CS8417: @@ -247,9 +196,7 @@ class Program { static async Task Main() { - // error CS8417: 'Example': type used in an asynchronous using statement - // must implement 'System.IAsyncDisposable' or implement a suitable - // 'DisposeAsync' method. Did you mean 'using' rather than 'await using'? + // error CS8417: type implements IDisposable, not IAsyncDisposable await using var example = new Example(); } } @@ -260,18 +207,6 @@ class Example : IDisposable } ``` -To correct this error, either: -- Change `await using` to `using` if synchronous disposal is appropriate -- Implement if asynchronous disposal is needed - -For more information, see [Implement a DisposeAsync method](../../../standard/garbage-collection/implementing-disposeasync.md). - -## Disposable type used with `await using` - -- **CS8418**: *'type': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'?* - -You used a synchronous `using` statement with a type that implements but not . The compiler suggests you might have meant to use `await using` instead. - The following example generates CS8418: ```csharp @@ -282,8 +217,7 @@ class Program { static async Task Main() { - // error CS8418: 'Example': type used in a using statement must implement - // 'System.IDisposable'. Did you mean 'await using' rather than 'using'? + // error CS8418: type implements IAsyncDisposable, not IDisposable using var example = new Example(); } } @@ -294,15 +228,69 @@ class Example : IAsyncDisposable } ``` -To correct this error, either: -- Change `using` to `await using` if asynchronous disposal is appropriate -- Implement if synchronous disposal is needed +To correct these errors, use the appropriate disposal pattern: +- Use synchronous `using` for types that implement +- Use `await using` for types that implement +- If both patterns are needed, implement both interfaces + +For more information, see [Finalizers](../../programming-guide/classes-and-structs/finalizers.md), [Implement a Dispose method](../../../standard/garbage-collection/implementing-dispose.md), and [Implement a DisposeAsync method](../../../standard/garbage-collection/implementing-disposeasync.md). + +## Using variable scope and control flow + +The following compiler errors and warnings relate to incorrect usage of `using` variables within control flow statements: + +- CS0728 +- CS8647 +- CS8648 +- CS8649 + +Variables declared with `using` have specific scoping rules that prevent resource leaks. The compiler enforces these rules to ensure proper disposal. + +### Assignment to using variable (CS0728) + +This warning indicates that you assigned a new value to a variable that is the resource in a `using` statement. The dispose call will occur on the original value, not the newly assigned value, which can lead to resource leaks. + +The following example generates CS0728: + +```csharp +using System; + +public class ValidBase : IDisposable +{ + public void Dispose() { } +} + +public class Program +{ + public static void Main() + { + ValidBase vb = null; + using (vb) + { + vb = new ValidBase(); // CS0728: assignment to using variable + } + // The Dispose call happens on null, not on the newly created ValidBase object + } +} +``` + +To correct this error, initialize the resource in the `using` statement declaration: + +```csharp +using (ValidBase vb = new ValidBase()) +{ + // Use vb +} +``` -For more information, see [Implement a DisposeAsync method](../../../standard/garbage-collection/implementing-disposeasync.md). +Or with a `using` declaration: -## Using variable in switch section +```csharp +using ValidBase vb = new ValidBase(); +// Use vb +``` -- **CS8647**: *A using variable cannot be used directly within a switch section (consider using braces).* +### Using variable in switch section (CS8647) A `using` declaration creates a variable that is disposed at the end of its scope. When used directly in a switch section without braces, the scope is ambiguous and can lead to errors. @@ -348,15 +336,11 @@ switch (choice) } ``` -For more information, see [using statement](../statements/using.md). - -## Goto forward jump over using declaration - -- **CS8648**: *A goto cannot jump to a location after a using declaration.* +### Goto statements and using declarations (CS8648, CS8649) -You cannot use a `goto` statement to jump forward over a `using` declaration. The `using` declaration creates a resource that must be properly disposed, and jumping over it would skip the resource initialization. +You can't use `goto` statements to jump over `using` declarations. The `using` declaration creates a resource that must be properly disposed, and jumping over it would skip proper resource management. -The following example generates CS8648: +The following example generates CS8648 when jumping forward over a `using` declaration: ```csharp using System; @@ -381,20 +365,7 @@ class Resource : IDisposable } ``` -To correct this error, restructure your code to avoid jumping over the `using` declaration. You can: -- Move the `using` declaration before the label -- Remove the `goto` statement and use structured control flow -- Place the `using` declaration in a separate scope - -For more information, see [using statement](../statements/using.md). - -## Goto backward jump over using declaration - -- **CS8649**: *A goto cannot jump to a location before a using declaration within the same block.* - -You cannot use a `goto` statement to jump backward to a location before a `using` declaration within the same block. This would create a control flow that could skip proper disposal of the resource. - -The following example generates CS8649: +The following example generates CS8649 when jumping backward to a location before a `using` declaration: ```csharp using System; @@ -420,10 +391,10 @@ class Resource : IDisposable } ``` -To correct this error, restructure your code to avoid jumping backward over the `using` declaration. You can: +To correct these errors, restructure your code to avoid jumping over `using` declarations: - Remove the `goto` statement and use structured control flow like loops -- Place the `using` declaration in a separate scope outside the jump target -- Restructure the logic to avoid the backward jump +- Move the `using` declaration before jump labels or to a separate scope +- Restructure the logic to avoid jumps across resource declarations For more information, see [using statement](../statements/using.md). @@ -437,4 +408,35 @@ A variable declaration wrapped in a `using` declaration can't include any of the - `static` - `volatile` - `readonly` -- Acccessibility modifiers: `public`, `protected`, `internal`, `private`, `protected internal` or `private protected` +- Accessibility modifiers: `public`, `protected`, `internal`, `private`, `protected internal`, or `private protected` + +The following example generates CS9229: + +```csharp +using System; + +class Program +{ + static void Main() + { + // error CS9229: Modifiers cannot be placed on using declarations. + public using var resource = new Resource(); + + // error CS9229: Modifiers cannot be placed on using declarations. + static using var anotherResource = new Resource(); + } +} + +class Resource : IDisposable +{ + public void Dispose() { } +} +``` + +To correct this error, remove the modifier from the `using` declaration: + +```csharp +using var resource = new Resource(); +``` + +For more information, see [using statement](../statements/using.md). From 359a513a35832daf28bd84773485dedfc6fc68a4 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 27 Oct 2025 15:24:44 -0400 Subject: [PATCH 6/7] A final proofread --- .../using-statement-declaration-errors.md | 364 ++---------------- 1 file changed, 24 insertions(+), 340 deletions(-) diff --git a/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md b/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md index f3dbbb7d1c255..65e7f98a6de18 100644 --- a/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md +++ b/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md @@ -33,205 +33,33 @@ This article covers the following compiler errors: -- [**CS0245**](#implementing-idisposable-and-iasyncdisposable): *Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available.* -- [**CS0728**](#using-variable-scope-and-control-flow): *Possibly incorrect assignment to local 'variable' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.* -- [**CS1674**](#implementing-idisposable-and-iasyncdisposable): *'T': type used in a using statement must be implicitly convertible to 'System.IDisposable'* -- [**CS8410**](#implementing-idisposable-and-iasyncdisposable): *'type': type used in an asynchronous `using` statement must be implicitly convertible to 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method.* -- [**CS8417**](#implementing-idisposable-and-iasyncdisposable): *'type': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'?* -- [**CS8418**](#implementing-idisposable-and-iasyncdisposable): *'type': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'?* +- [**CS0245**](#implementing-idisposable-and-iasyncdisposable): *Destructors and `object.Finalize` cannot be called directly. Consider calling `IDisposable.Dispose` if available.* +- [**CS0728**](#using-variable-scope-and-control-flow): *Possibly incorrect assignment to local variable which is the argument to a using or `lock` statement. The `Dispose` call or unlocking will happen on the original value of the local.* +- [**CS1674**](#implementing-idisposable-and-iasyncdisposable): *Type used in a using statement must be implicitly convertible to '`System.IDisposable`'.* +- [**CS8410**](#implementing-idisposable-and-iasyncdisposable): *'Type used in an asynchronous `using` statement must be implicitly convertible to '`System.IAsyncDisposable`' or implement a suitable '`DisposeAsync`' method.* +- [**CS8417**](#implementing-idisposable-and-iasyncdisposable): *Type used in an asynchronous using statement must implement '`System.IAsyncDisposable`' or implement a suitable '`DisposeAsync`' method. Did you mean '`using`' rather than '`await using`'?* +- [**CS8418**](#implementing-idisposable-and-iasyncdisposable): *Type used in a using statement must implement '`System.IDisposable`'. Did you mean '`await using`' rather than 'using'?* - [**CS8647**](#using-variable-scope-and-control-flow): *A using variable cannot be used directly within a switch section (consider using braces).* -- [**CS8648**](#using-variable-scope-and-control-flow): *A goto cannot jump to a location after a using declaration.* -- [**CS8649**](#using-variable-scope-and-control-flow): *A goto cannot jump to a location before a using declaration within the same block.* +- [**CS8648**](#using-variable-scope-and-control-flow): *A `goto` cannot jump to a location after a using declaration.* +- [**CS8649**](#using-variable-scope-and-control-flow): *A `goto` cannot jump to a location before a using declaration within the same block.* - [**CS9229**](#incorrect-using-declaration): *Modifiers cannot be placed on using declarations.* ## Implementing IDisposable and IAsyncDisposable The following compiler errors and warnings indicate issues with implementing or using the dispose pattern: -- **CS0245**: *Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available.* -- **CS1674**: *'T': type used in a using statement must be implicitly convertible to 'System.IDisposable'* -- **CS8410**: *'type': type used in an asynchronous `using` statement must be implicitly convertible to 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method.* -- **CS8417**: *'type': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'?* -- **CS8418**: *'type': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'?* +- **CS0245**: *Destructors and `object.Finalize` cannot be called directly. Consider calling `IDisposable.Dispose` if available.* +- **CS1674**: *Type used in a using statement must be implicitly convertible to '`System.IDisposable`'.* +- **CS8410**: *Type used in an asynchronous `using` statement must be implicitly convertible to '`System.IAsyncDisposable`' or implement a suitable 'DisposeAsync' method.* +- **CS8417**: *Type used in an asynchronous `using` statement must implement '`System.IAsyncDisposable`' or implement a suitable '`DisposeAsync`' method. Did you mean '`using`' rather than '`await using`'?* +- **CS8418**: *Type used in a using statement must implement '`System.IDisposable`'. Did you mean '`await using`' rather than '`using`'?* The [using statement](../statements/using.md) ensures proper disposal of resources at the end of the `using` block. To use a type with a `using` statement, it must implement the appropriate disposal interface. For synchronous `using` statements, the type must implement . For asynchronous `await using` statements, the type must implement . -### Cannot call Finalize directly (CS0245) - -You cannot directly call a destructor (finalizer) or the method. The garbage collector automatically calls finalizers when an object is no longer referenced. If you need deterministic cleanup, implement the interface and call the `Dispose` method. - -The following example generates CS0245: - -```csharp -using System; - -class MyClass -{ - void Method() - { - this.Finalize(); // CS0245: cannot call Finalize directly - } - - public static void Main() { } -} -``` - -To correct this error, implement and call `Dispose`: - -```csharp -using System; - -class MyClass : IDisposable -{ - public void Dispose() - { - // Cleanup code goes here - GC.SuppressFinalize(this); - } - - void Method() - { - this.Dispose(); // Correct: call Dispose instead - } - - public static void Main() { } -} -``` - -### Type must implement IDisposable (CS1674) - -Only types that are disposable can be used in a `using` statement. For example, value types aren't disposable, and type parameters that aren't constrained to be classes can't be assumed to be disposable. - -The following sample generates CS1674: - -```csharp -class C -{ - public static void Main() - { - int a = 0; - a++; - using (a) {} // CS1674: int doesn't implement IDisposable - } -} -``` - -The following sample also generates CS1674: - -```csharp -using System; - -class C { - public void Test() { - using (C c = new C()) {} // CS1674: C doesn't implement IDisposable - } -} - -// OK - implements IDisposable -class D : IDisposable { - void IDisposable.Dispose() {} - public void Dispose() {} - - public static void Main() { - using (D d = new D()) {} - } -} -``` - -The following case illustrates the need for a class type constraint to guarantee that an unknown type parameter is disposable. The following sample generates CS1674: - -```csharp -using System; - -public class C -// Add a class type constraint that specifies a disposable class. -// Uncomment the following line to resolve. -// public class C where T : IDisposable -{ - public void F(T t) - { - using (t) {} // CS1674: T might not implement IDisposable - } -} -``` - -### Type must implement IAsyncDisposable (CS8410) - -The expression inside an `await using` statement must have a `DisposeAsync` method. Types used with `await using` must implement or provide a suitable `DisposeAsync` method. - -The following example generates CS8410: - -```csharp -using System.Threading.Tasks; - -class Program -{ - static async Task Main() - { - // error CS8410: 'Example': type used in an asynchronous using statement - // must be implicitly convertible to 'System.IAsyncDisposable' or implement - // a suitable 'DisposeAsync' method. - await using var example = new Example(); - } -} - -class Example -{ -} -``` - -To correct this error, remove the `await using` keywords, or implement a suitable `DisposeAsync` method. - -### Mismatched disposal pattern (CS8417, CS8418) - -These errors occur when you use the wrong disposal keyword for a type. CS8417 occurs when you use `await using` with a type that only implements (not ). CS8418 occurs when you use synchronous `using` with a type that only implements (not ). - -The following example generates CS8417: - -```csharp -using System; -using System.Threading.Tasks; - -class Program -{ - static async Task Main() - { - // error CS8417: type implements IDisposable, not IAsyncDisposable - await using var example = new Example(); - } -} - -class Example : IDisposable -{ - public void Dispose() { } -} -``` - -The following example generates CS8418: - -```csharp -using System; -using System.Threading.Tasks; - -class Program -{ - static async Task Main() - { - // error CS8418: type implements IAsyncDisposable, not IDisposable - using var example = new Example(); - } -} - -class Example : IAsyncDisposable -{ - public ValueTask DisposeAsync() => ValueTask.CompletedTask; -} -``` - -To correct these errors, use the appropriate disposal pattern: -- Use synchronous `using` for types that implement -- Use `await using` for types that implement -- If both patterns are needed, implement both interfaces +- **Cannot call Finalize directly (CS0245)**: You can't directly call a destructor or the method. The garbage collector automatically invokes finalizers when objects are no longer referenced. For deterministic cleanup, implement and call the `Dispose` method instead. +- **Type must implement IDisposable (CS1674)**: Only types that implement can be used in a `using` statement. Value types don't implement this interface, and generic type parameters without proper constraints can't be assumed to be disposable. Apply a type constraint like `where T : IDisposable` when working with generic types. +- **Type must implement IAsyncDisposable (CS8410)**: Types used with `await using` must implement or provide a suitable `DisposeAsync` method. If your type doesn't support asynchronous disposal, use a synchronous `using` statement instead or implement the required interface. +- **Mismatched disposal pattern (CS8417, CS8418)**: CS8417 occurs when you use `await using` with a type that only implements . CS8418 occurs when you use synchronous `using` with a type that only implements . Match the `using` keyword to the interface your type implements, or implement both interfaces if you need to support both patterns. For more information, see [Finalizers](../../programming-guide/classes-and-structs/finalizers.md), [Implement a Dispose method](../../../standard/garbage-collection/implementing-dispose.md), and [Implement a DisposeAsync method](../../../standard/garbage-collection/implementing-disposeasync.md). @@ -239,162 +67,18 @@ For more information, see [Finalizers](../../programming-guide/classes-and-struc The following compiler errors and warnings relate to incorrect usage of `using` variables within control flow statements: -- CS0728 -- CS8647 -- CS8648 -- CS8649 +- **CS0728**: *Possibly incorrect assignment to local variable which is the argument to a `using` or `lock` statement. The `Dispose` call or unlocking will happen on the original value of the local.* +- **CS8647**: *A using variable cannot be used directly within a switch section (consider using braces).* +- **CS8648**: *A `goto` cannot jump to a location after a using declaration.* +- **CS8649**: *A `goto` cannot jump to a location before a using declaration within the same block.* Variables declared with `using` have specific scoping rules that prevent resource leaks. The compiler enforces these rules to ensure proper disposal. -### Assignment to using variable (CS0728) - -This warning indicates that you assigned a new value to a variable that is the resource in a `using` statement. The dispose call will occur on the original value, not the newly assigned value, which can lead to resource leaks. - -The following example generates CS0728: - -```csharp -using System; - -public class ValidBase : IDisposable -{ - public void Dispose() { } -} - -public class Program -{ - public static void Main() - { - ValidBase vb = null; - using (vb) - { - vb = new ValidBase(); // CS0728: assignment to using variable - } - // The Dispose call happens on null, not on the newly created ValidBase object - } -} -``` - -To correct this error, initialize the resource in the `using` statement declaration: - -```csharp -using (ValidBase vb = new ValidBase()) -{ - // Use vb -} -``` - -Or with a `using` declaration: - -```csharp -using ValidBase vb = new ValidBase(); -// Use vb -``` - -### Using variable in switch section (CS8647) - -A `using` declaration creates a variable that is disposed at the end of its scope. When used directly in a switch section without braces, the scope is ambiguous and can lead to errors. - -The following example generates CS8647: - -```csharp -using System; - -class Program -{ - static void Main() - { - int choice = 1; - switch (choice) - { - case 1: - // error CS8647: A using variable cannot be used directly within - // a switch section (consider using braces). - using var resource = new Resource(); - Console.WriteLine("Case 1"); - break; - } - } -} - -class Resource : IDisposable -{ - public void Dispose() { } -} -``` +- **Assignment to using variable (CS0728)**: This warning indicates you assigned a new value to a variable that's the resource in a `using` statement. The dispose call occurs on the original value, not the newly assigned value, which can lead to resource leaks. Initialize the resource in the `using` statement declaration instead of assigning to it later. -To correct this error, wrap the switch section content in braces: - -```csharp -switch (choice) -{ - case 1: - { - using var resource = new Resource(); - Console.WriteLine("Case 1"); - break; - } -} -``` - -### Goto statements and using declarations (CS8648, CS8649) - -You can't use `goto` statements to jump over `using` declarations. The `using` declaration creates a resource that must be properly disposed, and jumping over it would skip proper resource management. - -The following example generates CS8648 when jumping forward over a `using` declaration: - -```csharp -using System; - -class Program -{ - static void Main() - { - goto label; - - // error CS8648: A goto cannot jump to a location after a using declaration. - using var resource = new Resource(); - - label: - Console.WriteLine("After label"); - } -} - -class Resource : IDisposable -{ - public void Dispose() { } -} -``` - -The following example generates CS8649 when jumping backward to a location before a `using` declaration: - -```csharp -using System; - -class Program -{ - static void Main() - { - label: - Console.WriteLine("At label"); - - using var resource = new Resource(); - - // error CS8649: A goto cannot jump to a location before a using - // declaration within the same block. - goto label; - } -} - -class Resource : IDisposable -{ - public void Dispose() { } -} -``` +- **Using variable in switch section (CS8647)**: A `using` declaration creates a variable that's disposed at the end of its scope. When used directly in a switch section without braces, the scope is ambiguous and can lead to errors. Wrap the switch section content in braces to clearly define the scope. -To correct these errors, restructure your code to avoid jumping over `using` declarations: -- Remove the `goto` statement and use structured control flow like loops -- Move the `using` declaration before jump labels or to a separate scope -- Restructure the logic to avoid jumps across resource declarations +- **Goto statements and using declarations (CS8648, CS8649)**: You can't use `goto` statements to jump over `using` declarations because jumping would skip proper resource management. CS8648 occurs when jumping forward over a `using` declaration, and CS8649 occurs when jumping backward to a location before a `using` declaration. Restructure your code to use structured control flow like loops, or move the `using` declaration outside the jump target. For more information, see [using statement](../statements/using.md). From 1b5c6ebb76848e597444169b8f8222401b8074f5 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 27 Oct 2025 15:38:19 -0400 Subject: [PATCH 7/7] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .openpublishing.redirection.csharp.json | 18 +++++++++--------- .../using-statement-declaration-errors.md | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.openpublishing.redirection.csharp.json b/.openpublishing.redirection.csharp.json index fd8d3d1af25de..cb45587fb53be 100644 --- a/.openpublishing.redirection.csharp.json +++ b/.openpublishing.redirection.csharp.json @@ -565,27 +565,27 @@ }, { "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs8410.md", - "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#type-must-be-async-disposable" + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#implementing-idisposable-and-iasyncdisposable" }, { "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs8417.md", - "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#async-disposable-type-used-with-using" + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#implementing-idisposable-and-iasyncdisposable" }, { "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs8418.md", - "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#disposable-type-used-with-await-using" + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#implementing-idisposable-and-iasyncdisposable" }, { "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs8647.md", - "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#using-variable-in-switch-section" + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#using-variable-scope-and-control-flow" }, { "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs8648.md", - "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#goto-forward-jump-over-using-declaration" + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#using-variable-scope-and-control-flow" }, { "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs8649.md", - "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#goto-backward-jump-over-using-declaration" + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#using-variable-scope-and-control-flow" }, { "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs8795.md", @@ -1715,7 +1715,7 @@ }, { "source_path_from_root": "/docs/csharp/misc/cs0245.md", - "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#cannot-call-finalize-directly" + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#implementing-idisposable-and-iasyncdisposable" }, { "source_path_from_root": "/docs/csharp/misc/cs0254.md", @@ -1895,7 +1895,7 @@ }, { "source_path_from_root": "/docs/csharp/misc/cs0728.md", - "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#assignment-to-using-variable" + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#using-variable-scope-and-control-flow" }, { "source_path_from_root": "/docs/csharp/misc/cs1037.md", @@ -2319,7 +2319,7 @@ }, { "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1674.md", - "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#type-must-be-disposable" + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-statement-declaration-errors#implementing-idisposable-and-iasyncdisposable" }, { "source_path_from_root": "/docs/csharp/misc/cs1686.md", diff --git a/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md b/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md index 65e7f98a6de18..3724a15b661aa 100644 --- a/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md +++ b/docs/csharp/language-reference/compiler-messages/using-statement-declaration-errors.md @@ -1,5 +1,5 @@ --- -title: Resolve errors related to `using` statements and `using` declarations. +title: Resolve errors related to `using` statements and `using` declarations description: These errors indicate an incorrect use of the `using` statement or `using` declarations. Learn about the errors and how to fix them. f1_keywords: - "CS0245"