From c628d3f59f7d3dc7212af9b901eddcc70cd574de Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 13 Jul 2026 13:32:49 -0400 Subject: [PATCH 1/6] Create framewoork --- .../compiler-messages/foreach-diagnostics.md | 44 +++++++++++++++++++ docs/csharp/language-reference/toc.yml | 5 +++ ...n-t-have-specifics-on-this-csharp-error.md | 11 ----- 3 files changed, 49 insertions(+), 11 deletions(-) create mode 100644 docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md diff --git a/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md b/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md new file mode 100644 index 0000000000000..84f998fe8a3d5 --- /dev/null +++ b/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md @@ -0,0 +1,44 @@ +--- +title: "Resolve errors and warnings related to async enumerables, enumerables, and `foreach` statements" +description: "This article helps you diagnose and correct compiler errors and warnings related to async enumerables, enumerables, and foreach statements" +f1_keywords: + - "CS8412" + - "CS8413" + - "CS8414" + - "CS8415" + - "CS8419" + - "CS8420" + - "CS8424" + - "CS8425" + - "CS8426" +helpviewer_keywords: + - "CS8412" + - "CS8413" + - "CS8414" + - "CS8415" + - "CS8419" + - "CS8420" + - "CS8424" + - "CS8425" + - "CS8426" +ms.date: 07/13/2026 +ai-usage: ai-assisted +--- + +# Resolve errors and warnings for `foreach` statements and async enumerables + +This article covers the following compiler errors and warnings: + + + +- [**CS8412**](#anchor-tbd): *Asynchronous foreach requires that the return type 'type' of 'method' must have a suitable public 'MoveNextAsync' method and public 'Current' property* +- [**CS8413**](#anchor-tbd): *Asynchronous foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface'; try casting to a specific interface instantiation* +- [**CS8414**](#anchor-tbd): *foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'. Did you mean 'await foreach' rather than 'foreach'?* +- [**CS8415**](#anchor-tbd): *Asynchronous foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'. Did you mean 'foreach' rather than 'await foreach'?* +- [**CS8419**](#anchor-tbd): *The body of an async-iterator method must contain a 'yield' statement.* +- [**CS8420**](#anchor-tbd): *The body of an async-iterator method must contain a 'yield' statement. Consider removing 'async' from the method declaration or adding a 'yield' statement.* +- [**CS8424**](#anchor-tbd): *The EnumeratorCancellationAttribute applied to parameter 'name' will have no effect. The attribute is only effective on a parameter of type CancellationToken in an async-iterator method returning IAsyncEnumerable* +- [**CS8425**](#anchor-tbd): *Async-iterator 'method' has one or more parameters of type 'CancellationToken' but none of them is decorated with the 'EnumeratorCancellation' attribute, so the cancellation token parameter from the generated 'IAsyncEnumerable<>.GetAsyncEnumerator' will be unconsumed* +- [**CS8426**](#anchor-tbd): *The attribute [EnumeratorCancellation] cannot be used on multiple parameters* diff --git a/docs/csharp/language-reference/toc.yml b/docs/csharp/language-reference/toc.yml index 5c871285af4ec..93bd03b3de34c 100644 --- a/docs/csharp/language-reference/toc.yml +++ b/docs/csharp/language-reference/toc.yml @@ -622,6 +622,11 @@ items: yield return, yield break, CS1622, CS1624, CS1625, CS1626, CS1627, CS1629, CS1631, CS1637, CS4013, CS8154, CS8176, CS9237, CS9238, CS9239 + - name: foreach statements and async enumerables + href: ./compiler-messages/foreach-diagnostics.md + displayName: > + foreach, await foreach, async enumerable, GetAsyncEnumerator, IAsyncEnumerable, + CS8412, CS8413, CS8414, CS8415, CS8419, CS8420, CS8424, CS8425, CS8426 - name: Extension declarations href: ./compiler-messages/extension-declarations.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 9c6218dedcd3b..8e38f0e08b427 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 @@ -225,21 +225,10 @@ f1_keywords: - "CS8383" - "CS8384" # C# 8.0 diagnostics - ## Async enumerables - - "CS8412" - - "CS8413" - - "CS8414" - - "CS8415" - - "CS8419" - - "CS8420" ## Static local functions - "CS8421" ## Attributes - "CS8423" - ## More async enumerators - - "CS8424" - - "CS8425" - - "CS8426" ## Index and range - "CS8428" - "CS8429" From d374aa878c876a269c302a6eb3e69cdfe56f5d34 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 13 Jul 2026 14:47:45 -0400 Subject: [PATCH 2/6] First consolidation phase Consolidate existing diagnostic files. --- .openpublishing.redirection.csharp.json | 32 ++ .../compiler-messages/cs0446.md | 33 -- .../compiler-messages/cs1579.md | 74 ---- .../compiler-messages/cs1640.md | 57 --- .../compiler-messages/foreach-diagnostics.md | 377 ++++++++++++++++++ docs/csharp/language-reference/toc.yml | 80 +--- docs/csharp/misc/cs0202.md | 81 ---- docs/csharp/misc/cs0230.md | 50 --- docs/csharp/misc/cs0278.md | 34 -- docs/csharp/misc/cs0279.md | 44 -- docs/csharp/misc/cs0280.md | 56 --- 11 files changed, 429 insertions(+), 489 deletions(-) delete mode 100644 docs/csharp/language-reference/compiler-messages/cs0446.md delete mode 100644 docs/csharp/language-reference/compiler-messages/cs1579.md delete mode 100644 docs/csharp/language-reference/compiler-messages/cs1640.md delete mode 100644 docs/csharp/misc/cs0202.md delete mode 100644 docs/csharp/misc/cs0230.md delete mode 100644 docs/csharp/misc/cs0278.md delete mode 100644 docs/csharp/misc/cs0279.md delete mode 100644 docs/csharp/misc/cs0280.md diff --git a/.openpublishing.redirection.csharp.json b/.openpublishing.redirection.csharp.json index 25c1563e1f38b..e9be684712504 100644 --- a/.openpublishing.redirection.csharp.json +++ b/.openpublishing.redirection.csharp.json @@ -310,6 +310,10 @@ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0417.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors" }, + { + "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0446.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/foreach-diagnostics" + }, { "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0467.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/lambda-expression-errors" @@ -438,6 +442,10 @@ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1564.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line" }, + { + "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1579.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/foreach-diagnostics" + }, { "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1614.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/attribute-usage-errors" @@ -446,6 +454,10 @@ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1616.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line" }, + { + "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1640.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/foreach-diagnostics" + }, { "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1656.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/unsafe-code-errors" @@ -1848,6 +1860,10 @@ "source_path_from_root": "/docs/csharp/misc/cs0200.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors" }, + { + "source_path_from_root": "/docs/csharp/misc/cs0202.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/foreach-diagnostics" + }, { "source_path_from_root": "/docs/csharp/misc/cs0206.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/ref-modifiers-errors" @@ -1912,6 +1928,10 @@ "source_path_from_root": "/docs/csharp/misc/cs0227.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/unsafe-code-errors" }, + { + "source_path_from_root": "/docs/csharp/misc/cs0230.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/foreach-diagnostics" + }, { "source_path_from_root": "/docs/csharp/misc/cs0231.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/params-arrays" @@ -1988,6 +2008,18 @@ "source_path_from_root": "/docs/csharp/misc/cs0277.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/interface-implementation-errors" }, + { + "source_path_from_root": "/docs/csharp/misc/cs0278.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/foreach-diagnostics" + }, + { + "source_path_from_root": "/docs/csharp/misc/cs0279.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/foreach-diagnostics" + }, + { + "source_path_from_root": "/docs/csharp/misc/cs0280.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/foreach-diagnostics" + }, { "source_path_from_root": "/docs/csharp/misc/cs0282.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/partial-declarations" diff --git a/docs/csharp/language-reference/compiler-messages/cs0446.md b/docs/csharp/language-reference/compiler-messages/cs0446.md deleted file mode 100644 index 8291d78372202..0000000000000 --- a/docs/csharp/language-reference/compiler-messages/cs0446.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -description: "Compiler Error CS0446" -title: "Compiler Error CS0446" -ms.date: 07/20/2015 -f1_keywords: - - "CS0446" -helpviewer_keywords: - - "CS0446" -ms.assetid: d7a07e24-722e-484d-b6d7-ca809b51858f ---- -# Compiler Error CS0446 - -Foreach cannot operate on a 'Method or Delegate'. Did you intend to invoke the 'Method or Delegate'? - - This error is caused by specifying a method without parentheses or an anonymous method without parentheses in the part of the `foreach` statement where you would normally put a collection class. Note that it is valid, though unusual, to put a method call in that location, if the method returns a collection class. - -## Example - - The following code will generate CS0446. - -```csharp -// CS0446.cs -using System; -class Tester -{ - static void Main() - { - int[] intArray = new int[5]; - foreach (int i in M) { } // CS0446 - } - static void M() { } -} -``` diff --git a/docs/csharp/language-reference/compiler-messages/cs1579.md b/docs/csharp/language-reference/compiler-messages/cs1579.md deleted file mode 100644 index 07814fab8df20..0000000000000 --- a/docs/csharp/language-reference/compiler-messages/cs1579.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -description: "Compiler Error CS1579" -title: "Compiler Error CS1579" -ms.date: 05/24/2018 -f1_keywords: - - "CS1579" -helpviewer_keywords: - - "CS1579" -ms.assetid: 1eba84ce-58df-4fe3-9134-e26efefdc4ab ---- -# Compiler Error CS1579 - -foreach statement cannot operate on variables of type 'type1' because 'type2' does not contain a public definition for 'identifier' - -To iterate through a collection using the [foreach](../statements/iteration-statements.md#the-foreach-statement) statement, the collection must meet the following requirements: - -- Its type must include a public parameterless `GetEnumerator` method whose return type is either class, struct, or interface type. -- The return type of the `GetEnumerator` method must contain a public property named `Current` and a public parameterless method named `MoveNext` whose return type is . - -## Example - -The following sample generates CS1579 because the `MyCollection` class doesn't contain the public `GetEnumerator` method: - -```csharp -// CS1579.cs -using System; -public class MyCollection -{ - int[] items; - public MyCollection() - { - items = new int[5] {12, 44, 33, 2, 50}; - } - - // Delete the following line to resolve. - MyEnumerator GetEnumerator() - - // Uncomment the following line to resolve: - // public MyEnumerator GetEnumerator() - { - return new MyEnumerator(this); - } - - // Declare the enumerator class: - public class MyEnumerator - { - int nIndex; - MyCollection collection; - public MyEnumerator(MyCollection coll) - { - collection = coll; - nIndex = -1; - } - - public bool MoveNext() - { - nIndex++; - return (nIndex < collection.items.Length); - } - - public int Current => collection.items[nIndex]; - } - - public static void Main() - { - MyCollection col = new MyCollection(); - Console.WriteLine("Values in the collection are:"); - foreach (int i in col) // CS1579 - { - Console.WriteLine(i); - } - } -} -``` diff --git a/docs/csharp/language-reference/compiler-messages/cs1640.md b/docs/csharp/language-reference/compiler-messages/cs1640.md deleted file mode 100644 index e8132b01560cb..0000000000000 --- a/docs/csharp/language-reference/compiler-messages/cs1640.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -description: "Compiler Error CS1640" -title: "Compiler Error CS1640" -ms.date: 07/20/2015 -f1_keywords: - - "CS1640" -helpviewer_keywords: - - "CS1640" -ms.assetid: 1393668e-05e9-4dc2-9203-3d9c2933406f ---- -# Compiler Error CS1640 - -foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface', try casting to a specific interface instantiation - - The type inherits from two or more instances of IEnumerator\, which means there is not a unique enumeration of the type that `foreach` could use. Specify the type of IEnumerator\ or use another looping construct. - -## Example - - The following sample generates CS1640: - -```csharp -// CS1640.cs - -using System; -using System.Collections; -using System.Collections.Generic; - -public class C : IEnumerable, IEnumerable, IEnumerable -{ - IEnumerator IEnumerable.GetEnumerator() - { - yield break; - } - - IEnumerator IEnumerable.GetEnumerator() - { - yield break; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return (IEnumerator)((IEnumerable)this).GetEnumerator(); - } -} - -public class Test -{ - public static int Main() - { - foreach (int i in new C()){} // CS1640 - - // Try specifying the type of IEnumerable - // foreach (int i in (IEnumerable)new C()){} - return 1; - } -} -``` diff --git a/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md b/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md index 84f998fe8a3d5..fc17306af83bd 100644 --- a/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md +++ b/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md @@ -2,6 +2,14 @@ title: "Resolve errors and warnings related to async enumerables, enumerables, and `foreach` statements" description: "This article helps you diagnose and correct compiler errors and warnings related to async enumerables, enumerables, and foreach statements" f1_keywords: + - "CS0202" + - "CS0230" + - "CS0278" + - "CS0279" + - "CS0280" + - "CS0446" + - "CS1579" + - "CS1640" - "CS8412" - "CS8413" - "CS8414" @@ -12,6 +20,14 @@ f1_keywords: - "CS8425" - "CS8426" helpviewer_keywords: + - "CS0202" + - "CS0230" + - "CS0278" + - "CS0279" + - "CS0280" + - "CS0446" + - "CS1579" + - "CS1640" - "CS8412" - "CS8413" - "CS8414" @@ -33,6 +49,14 @@ This article covers the following compiler errors and warnings: That's by design. The text closely matches the text of the compiler error / warning for SEO purposes. --> +- [**CS0202**](#anchor-tbd): *foreach requires that the return type 'type' of 'type.GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property* +- [**CS0230**](#anchor-tbd): *Type and identifier are both required in a foreach statement* +- [**CS0278**](#anchor-tbd): *'type' does not implement the 'pattern name' pattern. 'method name' is ambiguous with 'method name'.* +- [**CS0279**](#anchor-tbd): *'type' does not implement the 'pattern name' pattern. 'method name' is not a public instance or extension method.* +- [**CS0280**](#anchor-tbd): *'type' does not implement the 'pattern name' pattern. 'method name' has the wrong signature.* +- [**CS0446**](#anchor-tbd): *Foreach cannot operate on a 'method group'. Did you intend to invoke the 'method group'?* +- [**CS1579**](#anchor-tbd): *foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'* +- [**CS1640**](#anchor-tbd): *foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface'; try casting to a specific interface instantiation* - [**CS8412**](#anchor-tbd): *Asynchronous foreach requires that the return type 'type' of 'method' must have a suitable public 'MoveNextAsync' method and public 'Current' property* - [**CS8413**](#anchor-tbd): *Asynchronous foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface'; try casting to a specific interface instantiation* - [**CS8414**](#anchor-tbd): *foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'. Did you mean 'await foreach' rather than 'foreach'?* @@ -42,3 +66,356 @@ That's by design. The text closely matches the text of the compiler error / warn - [**CS8424**](#anchor-tbd): *The EnumeratorCancellationAttribute applied to parameter 'name' will have no effect. The attribute is only effective on a parameter of type CancellationToken in an async-iterator method returning IAsyncEnumerable* - [**CS8425**](#anchor-tbd): *Async-iterator 'method' has one or more parameters of type 'CancellationToken' but none of them is decorated with the 'EnumeratorCancellation' attribute, so the cancellation token parameter from the generated 'IAsyncEnumerable<>.GetAsyncEnumerator' will be unconsumed* - [**CS8426**](#anchor-tbd): *The attribute [EnumeratorCancellation] cannot be used on multiple parameters* + +## CS0202 + +foreach requires that the return type 'type' of 'type.GetEnumerator()' must have a suitable public MoveNext method and public Current property + +A function, used to enable the use of foreach statements, cannot return a pointer or array; it must return an instance of a class that is able to act as an enumerator. The proper requirements to serve as an enumerator include a public Current property and a public MoveNext method. + +> [!NOTE] +> In C# 2.0, the compiler will automatically generate Current and MoveNext for you. For more information, see the code example in [Generic Interfaces](../../programming-guide/generics/generic-interfaces.md). + +The following sample generates CS0202: + +```csharp +// CS0202.cs + +public class C1 +{ + public int Current + { + get + { + return 0; + } + } + + public bool MoveNext () + { + return false; + } + + public static implicit operator C1 (int c1) + { + return 0; + } +} + +public class C2 +{ + public int Current + { + get + { + return 0; + } + } + + public bool MoveNext () + { + return false; + } + + public C1[] GetEnumerator () + // try the following line instead + // public C1 GetEnumerator () + { + return null; + } +} + +public class MainClass +{ + public static void Main () + { + C2 c2 = new C2(); + + foreach (C1 x in c2) // CS0202 + { + System.Console.WriteLine(x.Current); + } + } +} +``` + +## CS0230 + +Type and identifier are both required in a foreach statement + +A [foreach](../statements/iteration-statements.md#the-foreach-statement) statement was poorly formed. + +The following sample generates CS0230: + +```csharp +// CS0230.cs +class MyClass +{ + public static void Main() + { + int[] myarray = new int[3] {1,2,3}; + + foreach (int in myarray) // CS0230 + { + Console.WriteLine(x); + } + } +} +``` + +To resolve this error, specify both a type and an identifier in the `foreach` statement: + +```csharp +class MyClass +{ + public static void Main() + { + int[] myarray = new int[3] {1,2,3}; + + foreach (int x in myarray) // Both type (int) and identifier (x) are specified + { + Console.WriteLine(x); + } + } +} +``` + +## CS0278 + +'type' does not implement the 'pattern name' pattern. 'method name' is ambiguous with 'method name'. + +There are several statements in C# that rely on defined patterns, such as `foreach` and `using`. For example, the [`foreach` statement](../statements/iteration-statements.md#the-foreach-statement) relies on the collection class implementing the "enumerable" pattern. + +CS0278 can occur if the compiler is unable to make the match due to ambiguities. For example, the "enumerable" pattern requires that there be a method called `MoveNext`, and your code might contain two methods called `MoveNext`. The compiler will attempt to find an interface to use, but it is recommended that you determine and resolve the cause of the ambiguity. + +The following sample generates CS0278. + +```csharp +// CS0278.cs +using System.Collections.Generic; +public class myTest +{ + public static void TestForeach(W w) + where W: IEnumerable, IEnumerable + { + foreach (int i in w) {} // CS0278 + } +} +``` + +## CS0279 + +'type name' does not implement the 'pattern name' pattern. 'method name' is either static or not public. + +There are several statements in C# that rely on defined patterns, such as `foreach` and `using`. For example, `foreach` relies on the collection class implementing the enumerable pattern. This error occurs when the compiler is unable to make the match due to a method being declared `static` or not `public`. Methods in patterns are required to be instances of classes, and to be public. + +The following example generates CS0279: + +```csharp +// CS0279.cs + +using System; +using System.Collections; + +public class myTest : IEnumerable +{ + IEnumerator IEnumerable.GetEnumerator() + { + yield return 0; + } + + internal IEnumerator GetEnumerator() + { + yield return 0; + } + + public static void Main() + { + foreach (int i in new myTest()) {} // CS0279 + } +} +``` + +## CS0280 + +'type' does not implement the 'pattern name' pattern. 'method name' has the wrong signature. + +Two statements in C#, `foreach` and `using`, rely on predefined patterns, "collection" and "resource" respectively. This warning occurs when the compiler cannot match one of these statements to its pattern due to a method's incorrect signature. For example, the "collection" pattern requires that there be a method called which takes no parameters and returns a `boolean`. Your code might contain a method that has a parameter or perhaps returns an object. + +The "resource" pattern and `using` provide another example. The "resource" pattern requires the method; if you define a property with the same name, you will get this warning. + +To resolve this warning, ensure that the method signatures in your type match the signatures of the corresponding methods in the pattern, and ensure that you have no properties with the same name as a method required by the pattern. + +### Example + +The following sample generates CS0280. + +```csharp +// CS0280.cs +using System; +using System.Collections; + +public class ValidBase: IEnumerable +{ + IEnumerator IEnumerable.GetEnumerator() + { + yield return 0; + } + + internal IEnumerator GetEnumerator() + { + yield return 0; + } +} + +class Derived : ValidBase +{ + // field, not method + new public int GetEnumerator; +} + +public class Test +{ + public static void Main() + { + foreach (int i in new Derived()) {} // CS0280 + } +} +``` + +## CS0446 + +Foreach cannot operate on a 'Method or Delegate'. Did you intend to invoke the 'Method or Delegate'? + +This error is caused by specifying a method without parentheses or an anonymous method without parentheses in the part of the `foreach` statement where you would normally put a collection class. Note that it is valid, though unusual, to put a method call in that location, if the method returns a collection class. + +### Example + +The following code will generate CS0446. + +```csharp +// CS0446.cs +using System; +class Tester +{ + static void Main() + { + int[] intArray = new int[5]; + foreach (int i in M) { } // CS0446 + } + static void M() { } +} +``` + +## CS1579 + +foreach statement cannot operate on variables of type 'type1' because 'type2' does not contain a public definition for 'identifier' + +To iterate through a collection using the [foreach](../statements/iteration-statements.md#the-foreach-statement) statement, the collection must meet the following requirements: + +- Its type must include a public parameterless `GetEnumerator` method whose return type is either class, struct, or interface type. +- The return type of the `GetEnumerator` method must contain a public property named `Current` and a public parameterless method named `MoveNext` whose return type is . + +### Example + +The following sample generates CS1579 because the `MyCollection` class doesn't contain the public `GetEnumerator` method: + +```csharp +// CS1579.cs +using System; +public class MyCollection +{ + int[] items; + public MyCollection() + { + items = new int[5] {12, 44, 33, 2, 50}; + } + + // Delete the following line to resolve. + MyEnumerator GetEnumerator() + + // Uncomment the following line to resolve: + // public MyEnumerator GetEnumerator() + { + return new MyEnumerator(this); + } + + // Declare the enumerator class: + public class MyEnumerator + { + int nIndex; + MyCollection collection; + public MyEnumerator(MyCollection coll) + { + collection = coll; + nIndex = -1; + } + + public bool MoveNext() + { + nIndex++; + return (nIndex < collection.items.Length); + } + + public int Current => collection.items[nIndex]; + } + + public static void Main() + { + MyCollection col = new MyCollection(); + Console.WriteLine("Values in the collection are:"); + foreach (int i in col) // CS1579 + { + Console.WriteLine(i); + } + } +} +``` + +## CS1640 + +foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface', try casting to a specific interface instantiation + +The type inherits from two or more instances of IEnumerator\, which means there is not a unique enumeration of the type that `foreach` could use. Specify the type of IEnumerator\ or use another looping construct. + +### Example + +The following sample generates CS1640: + +```csharp +// CS1640.cs + +using System; +using System.Collections; +using System.Collections.Generic; + +public class C : IEnumerable, IEnumerable, IEnumerable +{ + IEnumerator IEnumerable.GetEnumerator() + { + yield break; + } + + IEnumerator IEnumerable.GetEnumerator() + { + yield break; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return (IEnumerator)((IEnumerable)this).GetEnumerator(); + } +} + +public class Test +{ + public static int Main() + { + foreach (int i in new C()){} // CS1640 + + // Try specifying the type of IEnumerable + // foreach (int i in (IEnumerable)new C()){} + return 1; + } +} +``` diff --git a/docs/csharp/language-reference/toc.yml b/docs/csharp/language-reference/toc.yml index 93bd03b3de34c..706d80428569d 100644 --- a/docs/csharp/language-reference/toc.yml +++ b/docs/csharp/language-reference/toc.yml @@ -495,13 +495,14 @@ items: - name: Feature or version missing href: ./compiler-messages/feature-version-errors.md displayName: > - CS0171, CS0188, CS0843, CS1617, CS1638, CS1738, CS8021, CS8022, CS8023, CS8024, CS8025, CS8026, - CS8058, CS8059, CS8107, CS8192, CS8302, CS8303, CS8304, CS8305, CS8306, CS8314, - CS8320, CS8370, CS8371, CS8400, CS8401, CS8511, CS8627, CS8630, CS8652, CS8701, - CS8702, CS8703, CS8704, CS8706, CS8707, CS8773, CS8830, CS8831, CS8888, CS8889, - CS8890, CS8891, CS8904, CS8912, CS8919, CS8929, CS8936, CS8957, CS8967, CS9014, - CS9015, CS9016, CS9017, CS9041, CS9058, CS9064, CS9103, CS9171, CS9194, CS9202, - CS9204, CS9240, CS9260, CS9268, CS9269, CS9271, CS9327, CS9328, CS9346, CS9352 + CS0171, CS0188, CS0843, CS1617, CS1638, CS1738, CS8021, CS8022, CS8023, CS8024, + CS8025, CS8026, CS8058, CS8059, CS8107, CS8192, CS8302, CS8303, CS8304, CS8305, + CS8306, CS8314, CS8320, CS8370, CS8371, CS8400, CS8401, CS8511, CS8627, CS8630, + CS8652, CS8701, CS8702, CS8703, CS8704, CS8706, CS8707, CS8773, CS8830, CS8831, + CS8888, CS8889, CS8890, CS8891, CS8904, CS8912, CS8919, CS8929, CS8936, CS8957, + CS8967, CS9014, CS9015, CS9016, CS9017, CS9041, CS9058, CS9064, CS9103, CS9171, + CS9194, CS9202, CS9204, CS9240, CS9260, CS9268, CS9269, CS9271, CS9327, CS9328, + CS9346, CS9352 - name: Assembly references href: ./compiler-messages/assembly-references.md displayName: > @@ -626,7 +627,8 @@ items: href: ./compiler-messages/foreach-diagnostics.md displayName: > foreach, await foreach, async enumerable, GetAsyncEnumerator, IAsyncEnumerable, - CS8412, CS8413, CS8414, CS8415, CS8419, CS8420, CS8424, CS8425, CS8426 + CS0202, CS0230, CS0278, CS0279, CS0280, CS0446, CS1579, CS1640, CS8412, CS8413, + CS8414, CS8415, CS8419, CS8420, CS8424, CS8425, CS8426 - name: Extension declarations href: ./compiler-messages/extension-declarations.md displayName: > @@ -692,11 +694,11 @@ items: - name: Lambda expressions href: ./compiler-messages/lambda-expression-errors.md displayName: > - CS0407, CS0428, CS0467, CS0748, CS0815, CS0828, CS0837, CS1065, CS1621, CS1628, CS1632, - CS1643, CS1660, CS1661, CS1662, CS1673, CS1676, CS1677, CS1678, CS1686, CS1688, - CS1706, CS1731, CS1732, CS1764, CS1911, CS1989, CS3006, CS8030, CS8175, CS8820, - CS8821, CS8916, CS8917, CS8934, CS8971, CS8972, CS8974, CS8975, CS9098, CS9099, - CS9100, CS9236 + CS0407, CS0428, CS0467, CS0748, CS0815, CS0828, CS0837, CS1065, CS1621, CS1628, + CS1632, CS1643, CS1660, CS1661, CS1662, CS1673, CS1676, CS1677, CS1678, CS1686, + CS1688, CS1706, CS1731, CS1732, CS1764, CS1911, CS1989, CS3006, CS8030, CS8175, + CS8820, CS8821, CS8916, CS8917, CS8934, CS8971, CS8972, CS8974, CS8975, CS9098, + CS9099, CS9100, CS9236 - name: Delegate and function pointer declarations href: ./compiler-messages/delegate-function-pointer-diagnostics.md displayName: > @@ -720,11 +722,11 @@ items: - name: Using directive and aliases href: ./compiler-messages/using-directive-errors.md displayName: > - CS0104, CS0105, CS0116, CS0138, CS0430, CS0431, CS0432, CS0434, CS0435, CS0436, CS0437, - CS0438, CS0439, CS0440, CS0518, CS0576, CS0687, CS1022, CS1529, - CS1537, CS1671, CS1679, CS1680, CS1681, CS1730, CS2034, CS7000, CS7007, CS7015, - CS7021, CS8019, CS8020, CS8083, CS8085, CS8914, CS8915, CS8933, CS8954, CS8955, CS8956, CS9130, - CS9131, CS9132, CS9133, CS9162 + CS0104, CS0105, CS0116, CS0138, CS0430, CS0431, CS0432, CS0434, CS0435, CS0436, + CS0437, CS0438, CS0439, CS0440, CS0518, CS0576, CS0687, CS1022, CS1529, CS1537, + CS1671, CS1679, CS1680, CS1681, CS1730, CS2034, CS7000, CS7007, CS7015, CS7021, + CS8019, CS8020, CS8083, CS8085, CS8914, CS8915, CS8933, CS8954, CS8955, CS8956, + CS9130, CS9131, CS9132, CS9133, CS9162 - name: Using statements and declarations href: ./compiler-messages/using-statement-declaration-errors.md displayName: > @@ -981,12 +983,8 @@ items: href: ../misc/cs0191.md - name: CS0198 href: ../misc/cs0198.md - - name: CS0200 - href: ./compiler-messages/property-declaration-errors.md - name: CS0201 href: ./compiler-messages/cs0201.md - - name: CS0202 - href: ../misc/cs0202.md - name: CS0204 href: ../misc/cs0204.md - name: CS0205 @@ -997,8 +995,6 @@ items: href: ../misc/cs0228.md - name: CS0229 href: ./compiler-messages/cs0229.md - - name: CS0230 - href: ../misc/cs0230.md - name: CS0236 href: ../misc/cs0236.md - name: CS0238 @@ -1047,14 +1043,10 @@ items: href: ../misc/cs0443.md - name: CS0445 href: ./compiler-messages/cs0445.md - - name: CS0446 - href: ./compiler-messages/cs0446.md - name: CS0462 href: ../misc/cs0462.md - name: CS0468 href: ../misc/cs0468.md - - name: CS0470 - href: ./compiler-messages/interface-implementation-errors.md - name: CS0471 href: ../misc/cs0471.md - name: CS0500 @@ -1097,26 +1089,14 @@ items: href: ../misc/cs0534.md - name: CS0537 href: ../misc/cs0537.md - - name: CS0538 - href: ./compiler-messages/interface-implementation-errors.md - - name: CS0539 - href: ./compiler-messages/interface-implementation-errors.md - - name: CS0541 - href: ./compiler-messages/interface-implementation-errors.md - name: CS0542 href: ../misc/cs0542.md - - name: CS0545 - href: ./compiler-messages/property-declaration-errors.md - name: CS0549 href: ../misc/cs0549.md - - name: CS0551 - href: ./compiler-messages/interface-implementation-errors.md - name: CS0569 href: ../misc/cs0569.md - name: CS0570 href: ./compiler-messages/cs0570.md - - name: CS0571 - href: ./compiler-messages/property-declaration-errors.md - name: CS0572 href: ../misc/cs0572.md - name: CS0574 @@ -1253,8 +1233,6 @@ items: href: ../misc/cs0833.md - name: CS0836 href: ../misc/cs0836.md - - name: CS0840 - href: ./compiler-messages/property-declaration-errors.md - name: CS0841 href: ../misc/cs0841.md - name: CS0842 @@ -1275,8 +1253,6 @@ items: href: ../misc/cs1010.md - name: CS1013 href: ../misc/cs1013.md - - name: CS1014 - href: ./compiler-messages/property-declaration-errors.md - name: CS1015 href: ../misc/cs1015.md - name: CS1017 @@ -1297,8 +1273,6 @@ items: href: ../misc/cs1036.md - name: CS1041 href: ../misc/cs1041.md - - name: CS1043 - href: ./compiler-messages/property-declaration-errors.md - name: CS1044 href: ../misc/cs1044.md - name: CS1055 @@ -1391,8 +1365,6 @@ items: href: ../misc/cs1575.md - name: CS1577 href: ../misc/cs1577.md - - name: CS1579 - href: ./compiler-messages/cs1579.md - name: CS1583 href: ../misc/cs1583.md - name: CS1585 @@ -1427,12 +1399,8 @@ items: href: ../misc/cs1620.md - name: CS1630 href: ../misc/cs1630.md - - name: CS1637 - href: ./compiler-messages/iterator-yield.md - name: CS1639 href: ../misc/cs1639.md - - name: CS1640 - href: ./compiler-messages/cs1640.md - name: CS1644 href: ./compiler-messages/cs1644.md - name: CS1646 @@ -1651,8 +1619,6 @@ items: href: ./compiler-messages/cs8355.md - name: CS8422 href: ./compiler-messages/cs8422.md - - name: CS9036 - href: ./compiler-messages/property-declaration-errors.md - name: CS9043 href: ./compiler-messages/cs9043.md - name: Level 1 warning messages @@ -1801,12 +1767,6 @@ items: href: ../misc/cs0252.md - name: CS0253 href: ../misc/cs0253.md - - name: CS0278 - href: ../misc/cs0278.md - - name: CS0279 - href: ../misc/cs0279.md - - name: CS0280 - href: ../misc/cs0280.md - name: CS0444 href: ../misc/cs0444.md - name: CS0458 diff --git a/docs/csharp/misc/cs0202.md b/docs/csharp/misc/cs0202.md deleted file mode 100644 index 4ba035827d1e6..0000000000000 --- a/docs/csharp/misc/cs0202.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -description: "Compiler Error CS0202" -title: "Compiler Error CS0202" -ms.date: 07/20/2015 -f1_keywords: - - "CS0202" -helpviewer_keywords: - - "CS0202" -ms.assetid: 7088850f-c206-4b95-9586-a0fa3d876c0c ---- -# Compiler Error CS0202 - -foreach requires that the return type 'type' of 'type.GetEnumerator()' must have a suitable public MoveNext method and public Current property - - A function, used to enable the use of foreach statements, cannot return a pointer or array; it must return an instance of a class that is able to act as an enumerator. The proper requirements to serve as an enumerator include a public Current property and a public MoveNext method. - -> [!NOTE] -> In C# 2.0, the compiler will automatically generate Current and MoveNext for you. For more information, see the code example in [Generic Interfaces](../programming-guide/generics/generic-interfaces.md). - - The following sample generates CS0202: - -```csharp -// CS0202.cs - -public class C1 -{ - public int Current - { - get - { - return 0; - } - } - - public bool MoveNext () - { - return false; - } - - public static implicit operator C1 (int c1) - { - return 0; - } -} - -public class C2 -{ - public int Current - { - get - { - return 0; - } - } - - public bool MoveNext () - { - return false; - } - - public C1[] GetEnumerator () - // try the following line instead - // public C1 GetEnumerator () - { - return null; - } -} - -public class MainClass -{ - public static void Main () - { - C2 c2 = new C2(); - - foreach (C1 x in c2) // CS0202 - { - System.Console.WriteLine(x.Current); - } - } -} -``` diff --git a/docs/csharp/misc/cs0230.md b/docs/csharp/misc/cs0230.md deleted file mode 100644 index 91f3a82660a7e..0000000000000 --- a/docs/csharp/misc/cs0230.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -description: "Compiler Error CS0230" -title: "Compiler Error CS0230" -ms.date: 07/20/2015 -f1_keywords: - - "CS0230" -helpviewer_keywords: - - "CS0230" -ms.assetid: 132e4623-d393-4a5f-a3f8-838a1bfbd1b3 ---- -# Compiler Error CS0230 - -Type and identifier are both required in a foreach statement - - A [foreach](../language-reference/statements/iteration-statements.md#the-foreach-statement) statement was poorly formed. - - The following sample generates CS0230: - -```csharp -// CS0230.cs -class MyClass -{ - public static void Main() - { - int[] myarray = new int[3] {1,2,3}; - - foreach (int in myarray) // CS0230 - { - Console.WriteLine(x); - } - } -} -``` - -and the sample below presents the same code, but with no CS0230 error: - -```csharp -class MyClass -{ - public static void Main() - { - int[] myarray = new int[3] {1,2,3}; - - foreach (int x in myarray) // Both type (int) and indentifier (x) are specified - { - Console.WriteLine(x); - } - } -} -``` diff --git a/docs/csharp/misc/cs0278.md b/docs/csharp/misc/cs0278.md deleted file mode 100644 index 29c4433b33b33..0000000000000 --- a/docs/csharp/misc/cs0278.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -description: "Compiler Warning (level 2) CS0278" -title: "Compiler Warning (level 2) CS0278" -ms.date: 07/20/2015 -f1_keywords: - - "CS0278" -helpviewer_keywords: - - "CS0278" -ms.assetid: 5418cbbe-bcec-4379-a6f6-410987beb96a ---- -# Compiler Warning (level 2) CS0278 - -'type' does not implement the 'pattern name' pattern. 'method name' is ambiguous with 'method name'. - -There are several statements in C# that rely on defined patterns, such as `foreach` and `using`. For example, the [`foreach` statement](../language-reference/statements/iteration-statements.md#the-foreach-statement) relies on the collection class implementing the "enumerable" pattern. - -CS0278 can occur if the compiler is unable to make the match due to ambiguities. For example, the "enumerable" pattern requires that there be a method called `MoveNext`, and your code might contain two methods called `MoveNext`. The compiler will attempt to find an interface to use, but it is recommended that you determine and resolve the cause of the ambiguity. - -## Example - - The following sample generates CS0278. - -```csharp -// CS0278.cs -using System.Collections.Generic; -public class myTest -{ - public static void TestForeach(W w) - where W: IEnumerable, IEnumerable - { - foreach (int i in w) {} // CS0278 - } -} -``` diff --git a/docs/csharp/misc/cs0279.md b/docs/csharp/misc/cs0279.md deleted file mode 100644 index 1219abfbd4d64..0000000000000 --- a/docs/csharp/misc/cs0279.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -description: "Compiler Warning (level 2) CS0279" -title: "Compiler Warning (level 2) CS0279" -ms.date: 07/20/2015 -f1_keywords: - - "CS0279" -helpviewer_keywords: - - "CS0279" -ms.assetid: 5e5faa8f-3d5b-4999-aa62-ff7f131a3e04 ---- -# Compiler Warning (level 2) CS0279 - -'type name' does not implement the 'pattern name' pattern. 'method name' is either static or not public. - - There are several statements in C# that rely on defined patterns, such as `foreach` and `using`. For example, `foreach` relies on the collection class implementing the enumerable pattern. This error occurs when the compiler is unable to make the match due to a method being declared `static` or not `public`. Methods in patterns are required to be instances of classes, and to be public. - -## Example - - The following example generates CS0279: - -```csharp -// CS0279.cs - -using System; -using System.Collections; - -public class myTest : IEnumerable -{ - IEnumerator IEnumerable.GetEnumerator() - { - yield return 0; - } - - internal IEnumerator GetEnumerator() - { - yield return 0; - } - - public static void Main() - { - foreach (int i in new myTest()) {} // CS0279 - } -} -``` diff --git a/docs/csharp/misc/cs0280.md b/docs/csharp/misc/cs0280.md deleted file mode 100644 index 3b2cf791395b1..0000000000000 --- a/docs/csharp/misc/cs0280.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -description: "Compiler Warning (level 2) CS0280" -title: "Compiler Warning (level 2) CS0280" -ms.date: 07/20/2015 -f1_keywords: - - "CS0280" -helpviewer_keywords: - - "CS0280" -ms.assetid: 9b453478-92aa-4fd2-9b87-780fd138603a ---- -# Compiler Warning (level 2) CS0280 - -'type' does not implement the 'pattern name' pattern. 'method name' has the wrong signature. - - Two statements in C#, **foreach** and **using**, rely on predefined patterns, "collection" and "resource" respectively. This warning occurs when the compiler cannot match one of these statements to its pattern due to a method's incorrect signature. For example, the "collection" pattern requires that there be a method called which takes no parameters and returns a `boolean`. Your code might contain a method that has a parameter or perhaps returns an object. - - The "resource" pattern and `using` provide another example. The "resource" pattern requires the method; if you define a property with the same name, you will get this warning. - - To resolve this warning, ensure that the method signatures in your type match the signatures of the corresponding methods in the pattern, and ensure that you have no properties with the same name as a method required by the pattern. - -## Example - - The following sample generates CS0280. - -```csharp -// CS0280.cs -using System; -using System.Collections; - -public class ValidBase: IEnumerable -{ - IEnumerator IEnumerable.GetEnumerator() - { - yield return 0; - } - - internal IEnumerator GetEnumerator() - { - yield return 0; - } -} - -class Derived : ValidBase -{ - // field, not method - new public int GetEnumerator; -} - -public class Test -{ - public static void Main() - { - foreach (int i in new Derived()) {} // CS0280 - } -} -``` From 2605d7573d689e19ca9449d58b2bfb6bc96d3d39 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 13 Jul 2026 15:07:59 -0400 Subject: [PATCH 3/6] Add remaining missing diagnostics --- .../compiler-messages/foreach-diagnostics.md | 18 ++++++++++++++++++ docs/csharp/language-reference/toc.yml | 4 ++-- ...on-t-have-specifics-on-this-csharp-error.md | 2 -- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md b/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md index fc17306af83bd..467c484d14264 100644 --- a/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md +++ b/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md @@ -10,6 +10,7 @@ f1_keywords: - "CS0446" - "CS1579" - "CS1640" + - "CS8186" - "CS8412" - "CS8413" - "CS8414" @@ -19,6 +20,7 @@ f1_keywords: - "CS8424" - "CS8425" - "CS8426" + - "CS9353" helpviewer_keywords: - "CS0202" - "CS0230" @@ -28,6 +30,7 @@ helpviewer_keywords: - "CS0446" - "CS1579" - "CS1640" + - "CS8186" - "CS8412" - "CS8413" - "CS8414" @@ -37,6 +40,7 @@ helpviewer_keywords: - "CS8424" - "CS8425" - "CS8426" + - "CS9353" ms.date: 07/13/2026 ai-usage: ai-assisted --- @@ -57,6 +61,7 @@ That's by design. The text closely matches the text of the compiler error / warn - [**CS0446**](#anchor-tbd): *Foreach cannot operate on a 'method group'. Did you intend to invoke the 'method group'?* - [**CS1579**](#anchor-tbd): *foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'* - [**CS1640**](#anchor-tbd): *foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface'; try casting to a specific interface instantiation* +- [**CS8186**](#anchor-tbd): *A foreach loop must declare its iteration variables.* - [**CS8412**](#anchor-tbd): *Asynchronous foreach requires that the return type 'type' of 'method' must have a suitable public 'MoveNextAsync' method and public 'Current' property* - [**CS8413**](#anchor-tbd): *Asynchronous foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface'; try casting to a specific interface instantiation* - [**CS8414**](#anchor-tbd): *foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'. Did you mean 'await foreach' rather than 'foreach'?* @@ -66,6 +71,7 @@ That's by design. The text closely matches the text of the compiler error / warn - [**CS8424**](#anchor-tbd): *The EnumeratorCancellationAttribute applied to parameter 'name' will have no effect. The attribute is only effective on a parameter of type CancellationToken in an async-iterator method returning IAsyncEnumerable* - [**CS8425**](#anchor-tbd): *Async-iterator 'method' has one or more parameters of type 'CancellationToken' but none of them is decorated with the 'EnumeratorCancellation' attribute, so the cancellation token parameter from the generated 'IAsyncEnumerable<>.GetAsyncEnumerator' will be unconsumed* - [**CS8426**](#anchor-tbd): *The attribute [EnumeratorCancellation] cannot be used on multiple parameters* +- [**CS9353**](#anchor-tbd): *'type' does not contain a definition for 'member' and no accessible extension method 'member' accepting a first argument of type 'type' could be found (did you mean to iterate over the async collection with 'await foreach' instead?)* ## CS0202 @@ -419,3 +425,15 @@ public class Test } } ``` + +## CS8186 + +A foreach loop must declare its iteration variables. + +This error occurs when you use a `foreach` statement without declaring a new iteration variable. You must specify both a type (or `var`) and an identifier for the loop variable. + +## CS9353 + +'type' does not contain a definition for 'member' and no accessible extension method 'member' accepting a first argument of type 'type' could be found (did you mean to iterate over the async collection with 'await foreach' instead?) + +This error occurs when you use a regular `foreach` on a type that only implements but not . To resolve this error, use `await foreach` instead of `foreach`. diff --git a/docs/csharp/language-reference/toc.yml b/docs/csharp/language-reference/toc.yml index 706d80428569d..1654d4c4eb8df 100644 --- a/docs/csharp/language-reference/toc.yml +++ b/docs/csharp/language-reference/toc.yml @@ -627,8 +627,8 @@ items: href: ./compiler-messages/foreach-diagnostics.md displayName: > foreach, await foreach, async enumerable, GetAsyncEnumerator, IAsyncEnumerable, - CS0202, CS0230, CS0278, CS0279, CS0280, CS0446, CS1579, CS1640, CS8412, CS8413, - CS8414, CS8415, CS8419, CS8420, CS8424, CS8425, CS8426 + CS0202, CS0230, CS0278, CS0279, CS0280, CS0446, CS1579, CS1640, CS8186, CS8412, + CS8413, CS8414, CS8415, CS8419, CS8420, CS8424, CS8425, CS8426, CS9353 - name: Extension declarations href: ./compiler-messages/extension-declarations.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 8e38f0e08b427..4ea353a2ab2cd 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 @@ -178,7 +178,6 @@ f1_keywords: - "CS8183" - "CS8184" - "CS8185" - - "CS8186" - "CS8187" - "CS8188" - "CS8189" @@ -251,7 +250,6 @@ f1_keywords: - "CS9349" - "CS9350" - "CS9351" - - "CS9353" # Collection arguments: - "CS9354" - "CS9355" From 50f111de53aa5c4eac2152607d98ad4c70236701 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 13 Jul 2026 15:38:06 -0400 Subject: [PATCH 4/6] First draft rework --- .../compiler-messages/foreach-diagnostics.md | 463 ++++-------------- 1 file changed, 92 insertions(+), 371 deletions(-) diff --git a/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md b/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md index 467c484d14264..37040961712e3 100644 --- a/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md +++ b/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md @@ -53,387 +53,108 @@ This article covers the following compiler errors and warnings: That's by design. The text closely matches the text of the compiler error / warning for SEO purposes. --> -- [**CS0202**](#anchor-tbd): *foreach requires that the return type 'type' of 'type.GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property* -- [**CS0230**](#anchor-tbd): *Type and identifier are both required in a foreach statement* -- [**CS0278**](#anchor-tbd): *'type' does not implement the 'pattern name' pattern. 'method name' is ambiguous with 'method name'.* -- [**CS0279**](#anchor-tbd): *'type' does not implement the 'pattern name' pattern. 'method name' is not a public instance or extension method.* -- [**CS0280**](#anchor-tbd): *'type' does not implement the 'pattern name' pattern. 'method name' has the wrong signature.* -- [**CS0446**](#anchor-tbd): *Foreach cannot operate on a 'method group'. Did you intend to invoke the 'method group'?* -- [**CS1579**](#anchor-tbd): *foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'* -- [**CS1640**](#anchor-tbd): *foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface'; try casting to a specific interface instantiation* -- [**CS8186**](#anchor-tbd): *A foreach loop must declare its iteration variables.* -- [**CS8412**](#anchor-tbd): *Asynchronous foreach requires that the return type 'type' of 'method' must have a suitable public 'MoveNextAsync' method and public 'Current' property* -- [**CS8413**](#anchor-tbd): *Asynchronous foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface'; try casting to a specific interface instantiation* -- [**CS8414**](#anchor-tbd): *foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'. Did you mean 'await foreach' rather than 'foreach'?* -- [**CS8415**](#anchor-tbd): *Asynchronous foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'. Did you mean 'foreach' rather than 'await foreach'?* -- [**CS8419**](#anchor-tbd): *The body of an async-iterator method must contain a 'yield' statement.* -- [**CS8420**](#anchor-tbd): *The body of an async-iterator method must contain a 'yield' statement. Consider removing 'async' from the method declaration or adding a 'yield' statement.* -- [**CS8424**](#anchor-tbd): *The EnumeratorCancellationAttribute applied to parameter 'name' will have no effect. The attribute is only effective on a parameter of type CancellationToken in an async-iterator method returning IAsyncEnumerable* -- [**CS8425**](#anchor-tbd): *Async-iterator 'method' has one or more parameters of type 'CancellationToken' but none of them is decorated with the 'EnumeratorCancellation' attribute, so the cancellation token parameter from the generated 'IAsyncEnumerable<>.GetAsyncEnumerator' will be unconsumed* -- [**CS8426**](#anchor-tbd): *The attribute [EnumeratorCancellation] cannot be used on multiple parameters* -- [**CS9353**](#anchor-tbd): *'type' does not contain a definition for 'member' and no accessible extension method 'member' accepting a first argument of type 'type' could be found (did you mean to iterate over the async collection with 'await foreach' instead?)* - -## CS0202 - -foreach requires that the return type 'type' of 'type.GetEnumerator()' must have a suitable public MoveNext method and public Current property - -A function, used to enable the use of foreach statements, cannot return a pointer or array; it must return an instance of a class that is able to act as an enumerator. The proper requirements to serve as an enumerator include a public Current property and a public MoveNext method. - -> [!NOTE] -> In C# 2.0, the compiler will automatically generate Current and MoveNext for you. For more information, see the code example in [Generic Interfaces](../../programming-guide/generics/generic-interfaces.md). - -The following sample generates CS0202: - -```csharp -// CS0202.cs - -public class C1 -{ - public int Current - { - get - { - return 0; - } - } - - public bool MoveNext () - { - return false; - } - - public static implicit operator C1 (int c1) - { - return 0; - } -} - -public class C2 -{ - public int Current - { - get - { - return 0; - } - } - - public bool MoveNext () - { - return false; - } - - public C1[] GetEnumerator () - // try the following line instead - // public C1 GetEnumerator () - { - return null; - } -} - -public class MainClass -{ - public static void Main () - { - C2 c2 = new C2(); - - foreach (C1 x in c2) // CS0202 - { - System.Console.WriteLine(x.Current); - } - } -} -``` - -## CS0230 - -Type and identifier are both required in a foreach statement - -A [foreach](../statements/iteration-statements.md#the-foreach-statement) statement was poorly formed. - -The following sample generates CS0230: - -```csharp -// CS0230.cs -class MyClass -{ - public static void Main() - { - int[] myarray = new int[3] {1,2,3}; - - foreach (int in myarray) // CS0230 - { - Console.WriteLine(x); - } - } -} -``` - -To resolve this error, specify both a type and an identifier in the `foreach` statement: - -```csharp -class MyClass -{ - public static void Main() - { - int[] myarray = new int[3] {1,2,3}; - - foreach (int x in myarray) // Both type (int) and identifier (x) are specified - { - Console.WriteLine(x); - } - } -} -``` - -## CS0278 - -'type' does not implement the 'pattern name' pattern. 'method name' is ambiguous with 'method name'. - -There are several statements in C# that rely on defined patterns, such as `foreach` and `using`. For example, the [`foreach` statement](../statements/iteration-statements.md#the-foreach-statement) relies on the collection class implementing the "enumerable" pattern. - -CS0278 can occur if the compiler is unable to make the match due to ambiguities. For example, the "enumerable" pattern requires that there be a method called `MoveNext`, and your code might contain two methods called `MoveNext`. The compiler will attempt to find an interface to use, but it is recommended that you determine and resolve the cause of the ambiguity. - -The following sample generates CS0278. - -```csharp -// CS0278.cs -using System.Collections.Generic; -public class myTest -{ - public static void TestForeach(W w) - where W: IEnumerable, IEnumerable - { - foreach (int i in w) {} // CS0278 - } -} -``` - -## CS0279 - -'type name' does not implement the 'pattern name' pattern. 'method name' is either static or not public. - -There are several statements in C# that rely on defined patterns, such as `foreach` and `using`. For example, `foreach` relies on the collection class implementing the enumerable pattern. This error occurs when the compiler is unable to make the match due to a method being declared `static` or not `public`. Methods in patterns are required to be instances of classes, and to be public. - -The following example generates CS0279: - -```csharp -// CS0279.cs - -using System; -using System.Collections; +- [**CS0202**](#enumerable-pattern-requirements): *foreach requires that the return type 'type' of 'type.GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property* +- [**CS0230**](#foreach-statement-syntax): *Type and identifier are both required in a foreach statement* +- [**CS0278**](#enumerable-pattern-requirements): *'type' does not implement the 'pattern name' pattern. 'method name' is ambiguous with 'method name'.* +- [**CS0279**](#enumerable-pattern-requirements): *'type' does not implement the 'pattern name' pattern. 'method name' is not a public instance or extension method.* +- [**CS0280**](#enumerable-pattern-requirements): *'type' does not implement the 'pattern name' pattern. 'method name' has the wrong signature.* +- [**CS0446**](#foreach-statement-syntax): *Foreach cannot operate on a 'method group'. Did you intend to invoke the 'method group'?* +- [**CS1579**](#enumerable-pattern-requirements): *foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'* +- [**CS1640**](#multiple-enumerable-implementations): *foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface'; try casting to a specific interface instantiation* +- [**CS8186**](#foreach-statement-syntax): *A foreach loop must declare its iteration variables.* +- [**CS8412**](#enumerable-pattern-requirements): *Asynchronous foreach requires that the return type 'type' of 'method' must have a suitable public 'MoveNextAsync' method and public 'Current' property* +- [**CS8413**](#multiple-enumerable-implementations): *Asynchronous foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface'; try casting to a specific interface instantiation* +- [**CS8414**](#mismatched-foreach-and-await-foreach): *foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'. Did you mean 'await foreach' rather than 'foreach'?* +- [**CS8415**](#mismatched-foreach-and-await-foreach): *Asynchronous foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'. Did you mean 'foreach' rather than 'await foreach'?* +- [**CS8419**](#async-iterator-method-body): *The body of an async-iterator method must contain a 'yield' statement.* +- [**CS8420**](#async-iterator-method-body): *The body of an async-iterator method must contain a 'yield' statement. Consider removing 'async' from the method declaration or adding a 'yield' statement.* +- [**CS8424**](#enumeratorcancellation-attribute-usage): *The EnumeratorCancellationAttribute applied to parameter 'name' will have no effect. The attribute is only effective on a parameter of type CancellationToken in an async-iterator method returning IAsyncEnumerable* +- [**CS8425**](#enumeratorcancellation-attribute-usage): *Async-iterator 'method' has one or more parameters of type 'CancellationToken' but none of them is decorated with the 'EnumeratorCancellation' attribute, so the cancellation token parameter from the generated 'IAsyncEnumerable<>.GetAsyncEnumerator' will be unconsumed* +- [**CS8426**](#enumeratorcancellation-attribute-usage): *The attribute [EnumeratorCancellation] cannot be used on multiple parameters* +- [**CS9353**](#mismatched-foreach-and-await-foreach): *'type' does not contain a definition for 'member' and no accessible extension method 'member' accepting a first argument of type 'type' could be found (did you mean to iterate over the async collection with 'await foreach' instead?)* -public class myTest : IEnumerable -{ - IEnumerator IEnumerable.GetEnumerator() - { - yield return 0; - } +## `foreach` statement syntax - internal IEnumerator GetEnumerator() - { - yield return 0; - } +- **CS0230**: *Type and identifier are both required in a foreach statement* +- **CS0446**: *Foreach cannot operate on a 'method group'. Did you intend to invoke the 'method group'?* +- **CS8186**: *A foreach loop must declare its iteration variables.* - public static void Main() - { - foreach (int i in new myTest()) {} // CS0279 - } -} -``` +These errors indicate that the [`foreach` statement](../statements/iteration-statements.md#the-foreach-statement) itself is malformed, regardless of whether the collection type is valid. -## CS0280 +Declare both a type (or `var`) and an identifier for the iteration variable (**CS0230**, **CS8186**). The `foreach` statement requires a loop variable declaration — you can't omit either the type or the name. For example, write `foreach (int x in collection)` rather than `foreach (int in collection)`. -'type' does not implement the 'pattern name' pattern. 'method name' has the wrong signature. +Invoke the method or delegate rather than passing it as a collection expression (**CS0446**). If you reference a method group or delegate without parentheses in the `in` clause, the compiler reports this error because it expects a collection value. Add parentheses to call the method, provided it returns an enumerable type: `foreach (var item in GetItems())`. -Two statements in C#, `foreach` and `using`, rely on predefined patterns, "collection" and "resource" respectively. This warning occurs when the compiler cannot match one of these statements to its pattern due to a method's incorrect signature. For example, the "collection" pattern requires that there be a method called which takes no parameters and returns a `boolean`. Your code might contain a method that has a parameter or perhaps returns an object. +## Enumerable pattern requirements -The "resource" pattern and `using` provide another example. The "resource" pattern requires the method; if you define a property with the same name, you will get this warning. - -To resolve this warning, ensure that the method signatures in your type match the signatures of the corresponding methods in the pattern, and ensure that you have no properties with the same name as a method required by the pattern. - -### Example - -The following sample generates CS0280. - -```csharp -// CS0280.cs -using System; -using System.Collections; - -public class ValidBase: IEnumerable -{ - IEnumerator IEnumerable.GetEnumerator() - { - yield return 0; - } - - internal IEnumerator GetEnumerator() - { - yield return 0; - } -} - -class Derived : ValidBase -{ - // field, not method - new public int GetEnumerator; -} - -public class Test -{ - public static void Main() - { - foreach (int i in new Derived()) {} // CS0280 - } -} -``` +- **CS0202**: *foreach requires that the return type 'type' of 'type.GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property* +- **CS0278**: *'type' does not implement the 'pattern name' pattern. 'method name' is ambiguous with 'method name'.* +- **CS0279**: *'type' does not implement the 'pattern name' pattern. 'method name' is not a public instance or extension method.* +- **CS0280**: *'type' does not implement the 'pattern name' pattern. 'method name' has the wrong signature.* +- **CS1579**: *foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'* +- **CS8412**: *Asynchronous foreach requires that the return type 'type' of 'method' must have a suitable public 'MoveNextAsync' method and public 'Current' property* -## CS0446 +The `foreach` statement uses a pattern-based approach rather than requiring a specific interface. For a type to be enumerable, it must provide: -Foreach cannot operate on a 'Method or Delegate'. Did you intend to invoke the 'Method or Delegate'? - -This error is caused by specifying a method without parentheses or an anonymous method without parentheses in the part of the `foreach` statement where you would normally put a collection class. Note that it is valid, though unusual, to put a method call in that location, if the method returns a collection class. - -### Example - -The following code will generate CS0446. - -```csharp -// CS0446.cs -using System; -class Tester -{ - static void Main() - { - int[] intArray = new int[5]; - foreach (int i in M) { } // CS0446 - } - static void M() { } -} -``` - -## CS1579 - -foreach statement cannot operate on variables of type 'type1' because 'type2' does not contain a public definition for 'identifier' - -To iterate through a collection using the [foreach](../statements/iteration-statements.md#the-foreach-statement) statement, the collection must meet the following requirements: - -- Its type must include a public parameterless `GetEnumerator` method whose return type is either class, struct, or interface type. -- The return type of the `GetEnumerator` method must contain a public property named `Current` and a public parameterless method named `MoveNext` whose return type is . - -### Example - -The following sample generates CS1579 because the `MyCollection` class doesn't contain the public `GetEnumerator` method: - -```csharp -// CS1579.cs -using System; -public class MyCollection -{ - int[] items; - public MyCollection() - { - items = new int[5] {12, 44, 33, 2, 50}; - } - - // Delete the following line to resolve. - MyEnumerator GetEnumerator() +- A public parameterless `GetEnumerator` method (or `GetAsyncEnumerator` for `await foreach`) whose return type is a class, struct, or interface. +- On the enumerator return type: a public `Current` property and a public parameterless `MoveNext` method returning `bool` (or `MoveNextAsync` returning `ValueTask` for async). - // Uncomment the following line to resolve: - // public MyEnumerator GetEnumerator() - { - return new MyEnumerator(this); - } - - // Declare the enumerator class: - public class MyEnumerator - { - int nIndex; - MyCollection collection; - public MyEnumerator(MyCollection coll) - { - collection = coll; - nIndex = -1; - } - - public bool MoveNext() - { - nIndex++; - return (nIndex < collection.items.Length); - } - - public int Current => collection.items[nIndex]; - } - - public static void Main() - { - MyCollection col = new MyCollection(); - Console.WriteLine("Values in the collection are:"); - foreach (int i in col) // CS1579 - { - Console.WriteLine(i); - } - } -} -``` - -## CS1640 - -foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface', try casting to a specific interface instantiation - -The type inherits from two or more instances of IEnumerator\, which means there is not a unique enumeration of the type that `foreach` could use. Specify the type of IEnumerator\ or use another looping construct. - -### Example - -The following sample generates CS1640: +For details on the enumerable pattern, see [Iteration statements - `foreach`](../statements/iteration-statements.md#the-foreach-statement). -```csharp -// CS1640.cs +Ensure `GetEnumerator` returns a proper enumerator type — not an array or pointer (**CS0202**). The return value must be a type that itself exposes `MoveNext` and `Current`. -using System; -using System.Collections; -using System.Collections.Generic; - -public class C : IEnumerable, IEnumerable, IEnumerable -{ - IEnumerator IEnumerable.GetEnumerator() - { - yield break; - } - - IEnumerator IEnumerable.GetEnumerator() - { - yield break; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return (IEnumerator)((IEnumerable)this).GetEnumerator(); - } -} +Add a public `GetEnumerator` method if the type doesn't have one (**CS1579**). Alternatively, implement or provide an extension method named `GetEnumerator`. For `await foreach`, provide `GetAsyncEnumerator` or implement . -public class Test -{ - public static int Main() - { - foreach (int i in new C()){} // CS1640 - - // Try specifying the type of IEnumerable - // foreach (int i in (IEnumerable)new C()){} - return 1; - } -} -``` - -## CS8186 - -A foreach loop must declare its iteration variables. - -This error occurs when you use a `foreach` statement without declaring a new iteration variable. You must specify both a type (or `var`) and an identifier for the loop variable. - -## CS9353 - -'type' does not contain a definition for 'member' and no accessible extension method 'member' accepting a first argument of type 'type' could be found (did you mean to iterate over the async collection with 'await foreach' instead?) - -This error occurs when you use a regular `foreach` on a type that only implements but not . To resolve this error, use `await foreach` instead of `foreach`. +Ensure that `GetAsyncEnumerator` returns a type with a public `MoveNextAsync` method returning `ValueTask` and a public `Current` property (**CS8412**). This is the async equivalent of **CS0202**. + +Resolve ambiguity when multiple methods match the pattern name (**CS0278**). This warning occurs when the compiler finds two candidates for `MoveNext` or `GetEnumerator`. Remove or rename the conflicting member, or cast to a specific interface to disambiguate. + +Make pattern methods public and non-static (**CS0279**). The enumerable pattern requires that `GetEnumerator`, `MoveNext`, and `Current` be public instance members (or public extension methods). Change `internal` or `static` members to `public` instance members. + +Correct the signature of pattern methods (**CS0280**). For example, `MoveNext` must take no parameters and return `bool`. If a field or property shadows the method name, rename it so the compiler can find the correct method. + +## Multiple enumerable implementations + +- **CS1640**: *foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface'; try casting to a specific interface instantiation* +- **CS8413**: *Asynchronous foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface'; try casting to a specific interface instantiation* + +These errors occur when the collection type implements multiple generic instantiations of (**CS1640**) or (**CS8413**), creating ambiguity about which element type to enumerate. + +Cast the collection to a specific interface instantiation before iterating. For example, if a type implements both `IEnumerable` and `IEnumerable`, write `foreach (int i in (IEnumerable)collection)` to select the desired element type. + +## Mismatched `foreach` and `await foreach` + +- **CS8414**: *foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'. Did you mean 'await foreach' rather than 'foreach'?* +- **CS8415**: *Asynchronous foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'. Did you mean 'foreach' rather than 'await foreach'?* +- **CS9353**: *'type' does not contain a definition for 'member' and no accessible extension method 'member' accepting a first argument of type 'type' could be found (did you mean to iterate over the async collection with 'await foreach' instead?)* + +These errors indicate a mismatch between the kind of `foreach` statement and the interfaces the collection type implements. + +Use `await foreach` instead of `foreach` when the collection implements only (**CS8414**, **CS9353**). Async-enumerable types provide `GetAsyncEnumerator` rather than `GetEnumerator`, so you must use `await foreach` in an `async` method to iterate them. + +Use `foreach` instead of `await foreach` when the collection implements only (**CS8415**). Synchronous collections don't provide `GetAsyncEnumerator`, so `await foreach` can't enumerate them. + +## Async iterator method body + +- **CS8419**: *The body of an async-iterator method must contain a 'yield' statement.* +- **CS8420**: *The body of an async-iterator method must contain a 'yield' statement. Consider removing 'async' from the method declaration or adding a 'yield' statement.* + +These errors fire when a method's signature declares it as an async iterator (it's `async` and returns or ) but the body contains no `yield return` or `yield break` statement. + +Add at least one `yield return` statement to the method body to make it a valid async-iterator method. If you didn't intend the method to be an iterator, remove the `async` modifier and change the return type, or return a constructed async enumerable from a different source instead. + +For more information on iterator methods, see [Iterators](../../iterators.md) and [`yield` statement](../statements/yield.md). + +## `EnumeratorCancellation` attribute usage + +- **CS8424**: *The EnumeratorCancellationAttribute applied to parameter 'name' will have no effect. The attribute is only effective on a parameter of type CancellationToken in an async-iterator method returning IAsyncEnumerable* +- **CS8425**: *Async-iterator 'method' has one or more parameters of type 'CancellationToken' but none of them is decorated with the 'EnumeratorCancellation' attribute, so the cancellation token parameter from the generated 'IAsyncEnumerable<>.GetAsyncEnumerator' will be unconsumed* +- **CS8426**: *The attribute [EnumeratorCancellation] cannot be used on multiple parameters* + +These diagnostics relate to the , which connects a parameter to the token supplied by . + +Apply `[EnumeratorCancellation]` only to a parameter of type in an async-iterator method that returns (**CS8424**). The attribute has no effect in any other context — non-token parameters, non-iterator methods, or methods returning other types. + +Add the `[EnumeratorCancellation]` attribute to exactly one `CancellationToken` parameter (**CS8425**). Without this attribute, the token provided by callers through `WithCancellation` is not forwarded to the iterator body. The generated `GetAsyncEnumerator(CancellationToken)` parameter goes unconsumed. + +Apply the attribute to only one parameter — not multiple (**CS8426**). The runtime infrastructure supports forwarding a single cancellation token to the iterator. If you have multiple token parameters, designate only one with the attribute and combine others manually using . From 7581c50e702460963eae36f3a111b143cbbc1aca Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 13 Jul 2026 15:51:40 -0400 Subject: [PATCH 5/6] Final review. --- .../compiler-messages/foreach-diagnostics.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md b/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md index 37040961712e3..a2f95ff8ae5c8 100644 --- a/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md +++ b/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md @@ -81,7 +81,7 @@ That's by design. The text closely matches the text of the compiler error / warn These errors indicate that the [`foreach` statement](../statements/iteration-statements.md#the-foreach-statement) itself is malformed, regardless of whether the collection type is valid. -Declare both a type (or `var`) and an identifier for the iteration variable (**CS0230**, **CS8186**). The `foreach` statement requires a loop variable declaration — you can't omit either the type or the name. For example, write `foreach (int x in collection)` rather than `foreach (int in collection)`. +Declare both a type (or `var`) and an identifier for the iteration variable (**CS0230**, **CS8186**). The `foreach` statement requires a loop variable declaration. You can't omit either the type or the name. For example, write `foreach (int x in collection)` rather than `foreach (int in collection)`. Invoke the method or delegate rather than passing it as a collection expression (**CS0446**). If you reference a method group or delegate without parentheses in the `in` clause, the compiler reports this error because it expects a collection value. Add parentheses to call the method, provided it returns an enumerable type: `foreach (var item in GetItems())`. @@ -139,7 +139,7 @@ Use `foreach` instead of `await foreach` when the collection implements only or ) but the body contains no `yield return` or `yield break` statement. +These errors occur when a method's signature declares it as an async iterator (it's `async` and returns or ) but the body contains no `yield return` or `yield break` statement. Add at least one `yield return` statement to the method body to make it a valid async-iterator method. If you didn't intend the method to be an iterator, remove the `async` modifier and change the return type, or return a constructed async enumerable from a different source instead. @@ -153,8 +153,8 @@ For more information on iterator methods, see [Iterators](../../iterators.md) an These diagnostics relate to the , which connects a parameter to the token supplied by . -Apply `[EnumeratorCancellation]` only to a parameter of type in an async-iterator method that returns (**CS8424**). The attribute has no effect in any other context — non-token parameters, non-iterator methods, or methods returning other types. +Apply `[EnumeratorCancellation]` only to a parameter of type in an async-iterator method that returns (**CS8424**). The attribute has no effect in any other context, such as non-token parameters, non-iterator methods, or methods returning other types. -Add the `[EnumeratorCancellation]` attribute to exactly one `CancellationToken` parameter (**CS8425**). Without this attribute, the token provided by callers through `WithCancellation` is not forwarded to the iterator body. The generated `GetAsyncEnumerator(CancellationToken)` parameter goes unconsumed. +Add the `[EnumeratorCancellation]` attribute to exactly one `CancellationToken` parameter (**CS8425**). Without this attribute, the token provided by callers through `WithCancellation` isn't forwarded to the iterator body. The generated `GetAsyncEnumerator(CancellationToken)` parameter goes unconsumed. -Apply the attribute to only one parameter — not multiple (**CS8426**). The runtime infrastructure supports forwarding a single cancellation token to the iterator. If you have multiple token parameters, designate only one with the attribute and combine others manually using . +Apply the attribute to only one parameter, not multiple (**CS8426**). The runtime infrastructure supports forwarding a single cancellation token to the iterator. If you have multiple token parameters, designate only one with the attribute and combine others manually using . From 8a0650e6c6c8bd06caee17fcaa92bdc9b2ce722a Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 13 Jul 2026 16:47:19 -0400 Subject: [PATCH 6/6] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../compiler-messages/foreach-diagnostics.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md b/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md index a2f95ff8ae5c8..b09f32813c884 100644 --- a/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md +++ b/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md @@ -97,15 +97,14 @@ Invoke the method or delegate rather than passing it as a collection expression The `foreach` statement uses a pattern-based approach rather than requiring a specific interface. For a type to be enumerable, it must provide: - A public parameterless `GetEnumerator` method (or `GetAsyncEnumerator` for `await foreach`) whose return type is a class, struct, or interface. -- On the enumerator return type: a public `Current` property and a public parameterless `MoveNext` method returning `bool` (or `MoveNextAsync` returning `ValueTask` for async). - +- On the enumerator return type: a public `Current` property and a public parameterless `MoveNext` method returning `bool` (or a public parameterless `MoveNextAsync` method that returns `Task`, `ValueTask`, or any other awaitable type whose awaiter's `GetResult` method returns a `bool` value). For details on the enumerable pattern, see [Iteration statements - `foreach`](../statements/iteration-statements.md#the-foreach-statement). Ensure `GetEnumerator` returns a proper enumerator type — not an array or pointer (**CS0202**). The return value must be a type that itself exposes `MoveNext` and `Current`. Add a public `GetEnumerator` method if the type doesn't have one (**CS1579**). Alternatively, implement or provide an extension method named `GetEnumerator`. For `await foreach`, provide `GetAsyncEnumerator` or implement . -Ensure that `GetAsyncEnumerator` returns a type with a public `MoveNextAsync` method returning `ValueTask` and a public `Current` property (**CS8412**). This is the async equivalent of **CS0202**. +Ensure that `GetAsyncEnumerator` returns a type with a public `Current` property and a public parameterless `MoveNextAsync` method that returns `Task`, `ValueTask`, or any other awaitable type whose awaiter's `GetResult` method returns a `bool` value (**CS8412**). This is the async equivalent of **CS0202**. Resolve ambiguity when multiple methods match the pattern name (**CS0278**). This warning occurs when the compiler finds two candidates for `MoveNext` or `GetEnumerator`. Remove or rename the conflicting member, or cast to a specific interface to disambiguate.