Water
Water

Reputation: 3715

Can you make a class enumerable via extension methods? In particular, System.Range

I'm using the latest C# 8 right now, I was toying around with the new System.Range, and wanted to see if something like

foreach (int i in 5..8)
{ 
}

was possible, but at the time of writing this (using the absolute cutting edge preview) is giving me an error.

I then wondered if I could make it enumerable by doing something like the following in a static class, since maybe the foreach loop doesn't actually care and just wants the existence of some method to be available, so I tried:

public static IEnumerator GetEnumerator(this Range range) 
{
    // ...
}

however the compiler was not happy with this.

Is this possible? Or am I just implementing enumerable wrong? The error message in the IDE was telling me that GetEnumerator() needs to be available for foreach to run, however since I don't have access to the class and can't simply do : IEnumerable<int> and then generate the methods from it and do what is needed, I don't know if this means I'm stuck or whether I'm coding this incorrectly.

My error:

    foreach (int i in 1..5)
    {
        Console.WriteLine(i);
    }

[CS1579] foreach statement cannot operate on variables of type 'Range' because 'Range' does not contain a public instance definition for 'GetEnumerator'

and

$ dotnet --version

3.0.100-preview8-013656

with a project targeting netcoreapp3.0 and the C# language level is preview

Upvotes: 1

Views: 375

Answers (1)

Jon Skeet
Jon Skeet

Reputation: 1503589

No, the foreach loop doesn't work with extension methods, unlike (say) await. It is pattern-based in that it doesn't require implementing IEnumerable<T> or IEnumerable - if you have an appropriate GetEnumerator() instance method returning an appropriate type (with MoveNext() and Current members), that's fine. But the compiler doesn't look for a GetEnumerator() extension method like you've got. It has been proposed, but I don't know of any plan to do this, and I'd be very surprised if it were in C# 8 (given the list of features).

You'd need to write an extension method like this:

 public static IEnumerable<int> AsEnumerable(this Range range)
 {
     ...
 }

and then you could use

 foreach (int x in (1..5).AsEnumerable())

... but you'd still need to work out what to do if either index is "from the end" instead of "from the start", and I'm not sure it's terribly useful to have that as an execution-time-only check, really.

Basically, ranges are designed mostly for slicing within another context rather than being standalone.

Upvotes: 6

Related Questions