Home > Software design >  Enumerable extension methods inaccessible on GroupCollection
Enumerable extension methods inaccessible on GroupCollection

Time:08-03

According to the documentation, the GroupCollection Class implements the generic IEnumerable interface. Its extension methods are even listed below on that page. Yet, I'm getting

Compilation error (line 16, col 4): 'GroupCollection' does not contain a definition for 'Skip' and no accessible extension method 'Skip' accepting a first argument of type 'GroupCollection' could be found (are you missing a using directive or an assembly reference?)

for the following code:

using System.Linq;
var currency = "HUF";
var origin = "Modlin";
var changes = 3;
System.Console.WriteLine(
    new[] {
        $"Cost: 50 {currency}",
        $"Departure airport: {origin}",
        $"Number of changes: {changes}"
    }[
        System.Text.RegularExpressions.Regex.Matches(
            "variable elem: blablaoriginbleble",
            "(currency)|(origin)|(changes)"
        )[0]
        .Groups
        .Skip(1)
        .Select((m, i) => (m, i))
        .First(p => p.Item1.Success)
        .Item2
    ]);

The error goes away if I surround L11-15 with ((System.Collections.Generic.IEnumerable<System.Text.RegularExpressions.Group>) and ). Why is it necessary?

What's even stranger is that omitting [0] and .Groups (not semantically equivalent, just for the sake of experiment) leads to no error as well. In that case the extension methods Skip, Select and First are called on an instance of MatchCollection. Which also implements IEnumerable and it seems behaviour should be analogous.

CodePudding user response:

EDIT 2:

I just tested your code in .NET 6 and got the same error message. I changed:

.Skip(1)

to:

.Skip<System.Text.RegularExpressions.Group>(1)

and it worked. I believe the issue is that, because GroupCollection implements IEnumerable<T> twice for two specific types T (Group and KeyValuePair<string,Group>>), the type cannot be inferred from usage. This means that you need to specify the generic type parameter when calling Skip so it knows which implementation to use. It's pretty much as you surmised in your comment on the question.

EDIT:

I'll leave my original answer below but, thinking about your code, it appears that you may be using top-level statements, so that would imply that you are using .NET 6. I guess we'll see when you respond. If you are then I'm not sure what the reason would be.

ORIGINAL:

That documentation is for .NET 6. I'm guessing that you're using an earlier version. You should select your .NET version in the upper-left of that page and I expect you'll find that, in that version, GroupCollection implements far fewer interfaces. For instance, it only implements ICollection in .NET Framework 4.8. What you can do is call Cast<T> to get an IEnumerable<T> and then access all the extensions methods for that interface:

using System.Linq;
using System.Text.RegularExpressions;

var currency = "HUF";
var origin = "Modlin";
var changes = 3;

System.Console.WriteLine(
    new[] {
        $"Cost: 50 {currency}",
        $"Departure airport: {origin}",
        $"Number of changes: {changes}"
    }[
        Regex.Matches(
            "variable elem: blablaoriginbleble",
            "(currency)|(origin)|(changes)"
        )[0]
        .Groups
        .Cast<Group>()
        .Skip(1)
        .Select((m, i) => (m, i))
        .First(p => p.Item1.Success)
        .Item2
    ]);
  • Related