How to Resolve Warning "CS0280: 'type' does not implement the 'pattern' pattern. 'method' has the wrong signature." in C#
The Compiler Warning CS0280 is a pattern matching validity warning. The message reads: "'MyType' does not implement the 'collection' pattern. 'GetEnumerator' has the wrong signature."
In C#, features like foreach, await, and using do not require your classes to implement specific interfaces (like IEnumerable or IDisposable) strictly. Instead, they look for specific methods by name (a concept known as Duck Typing). For foreach, the compiler looks for GetEnumerator(). If it finds a method with that name, but the method accepts arguments, returns void, or returns a type that isn't an enumerator, the compiler issues CS0280.
This guide explains the exact signature requirements for these C# patterns and how to fix them.
Understanding the Pattern Signature
For a foreach loop to iterate over MyCollection, the class must satisfy this contract:
- Method Name:
GetEnumerator - Parameters: Must take zero parameters.
- Return Type: Must return a class/struct that has a
MoveNext()method and aCurrentproperty.
If you have a method named GetEnumerator, but it requires an integer argument (e.g., GetEnumerator(int start)), the compiler matches the name but rejects the signature.
Scenario 1: GetEnumerator with Parameters
This is a common mistake when developers try to add configuration logic to the iteration start.
Example of error
You defined GetEnumerator to accept a parameter (like a sort flag or starting index).
using System.Collections;
public class DataList
{
private int[] _values = { 1, 2, 3 };
// ⛔️ Warning CS0280: 'GetEnumerator' has the wrong signature.
// The 'foreach' statement calls GetEnumerator() with NO arguments.
// It cannot use this method because it requires a boolean.
public IEnumerator GetEnumerator(bool reversed)
{
return _values.GetEnumerator();
}
}
public class Program
{
static void Main()
{
var list = new DataList();
// This loop fails to compile
foreach (var i in list) { }
}
}
Solution: Use a Parameterless Method
If you need parameters, create a separate method (like GetCustomEnumerator) and call that method explicitly in the foreach, but keep the standard GetEnumerator() parameterless.
using System.Collections;
public class DataList
{
private int[] _values = { 1, 2, 3 };
// ✅ Correct: Standard signature (No parameters)
public IEnumerator GetEnumerator()
{
return _values.GetEnumerator();
}
// Optional: Custom method for specific cases
public IEnumerator GetReversed() { /* logic */ return null; }
}
Scenario 2: Incorrect Return Type
The GetEnumerator method must return an object that acts as a cursor. If it returns void, int, or a class that misses the MoveNext/Current members, the signature is considered invalid for the pattern.
Example of error
Defining GetEnumerator to return nothing.
public class Logger
{
// ⛔️ Warning CS0280: 'GetEnumerator' has the wrong signature.
// It returns 'void'. The compiler expects an Enumerator object.
public void GetEnumerator()
{
System.Console.WriteLine("Iterating...");
}
}
public class Program
{
static void Main()
{
var log = new Logger();
foreach (var l in log) { } // Fails
}
}
Solution: Return an Enumerator
Return IEnumerator, IEnumerator<T>, or a custom struct that adheres to the enumerator pattern.
using System.Collections;
public class Logger : IEnumerable
{
// ✅ Correct: Returns a valid enumerator
public IEnumerator GetEnumerator()
{
return new ArrayList().GetEnumerator(); // Example return
}
}
Solution: Implement Standard Interfaces
The most robust way to avoid signature errors is to explicitly implement the IEnumerable interface. This forces the compiler to check your method signature against the interface contract immediately, providing clearer error messages if you get it wrong.
Solution:
using System.Collections;
using System.Collections.Generic;
// ✅ Correct: Implementing IEnumerable<T> ensures the signature is correct.
public class MyCollection : IEnumerable<int>
{
private List<int> _list = new List<int>();
// Required by IEnumerable<T>
public IEnumerator<int> GetEnumerator()
{
return _list.GetEnumerator();
}
// Required by IEnumerable (Legacy)
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Async Streams:
If you are using await foreach, the pattern looks for GetAsyncEnumerator(). The same rules apply: it must be parameterless (mostly) and return IAsyncEnumerator<T>.
Conclusion
CS0280 is the compiler telling you: "I found the method name I need for this loop, but I can't call it because the arguments or return type don't fit the rules."
- Check Parameters: Ensure
GetEnumerator()takes zero arguments. - Check Return Type: Ensure it returns an object that has
MoveNext()andCurrent. - Use Interfaces: Implementing
IEnumerableis the best way to prevent this warning.