Почему невозможно вызвать .ToArray непосредственно в GroupCollection, даже если это IEnumerable?

В соответствии с этим вопросом мне нужно указать, что GroupCollection является IEnumerable, чтобы использовать методы расширения, которые работают с IEnumerable на нем:

GroupCollection groups =  Regex.Match(content, @"key : (.+?)-").Groups;

IEnumerable<Group> groupsEnumerable = groups;

var foo = groupsEnumerable.Select(x=>x.Value).ToArray(); //this works fine
var bar = groups.Select(x=>x.Value).ToArray(); //while this does not compile

Почему я должен сообщать экземпляру GroupCollection, что это экземпляр IEnumerable, чтобы вызывать на нем методы расширения, основанные на IEnumerable?

Добавлен скриншот ошибки (.NET 6)

Неправда - и Regex.Match("aa", @"key : (.+?)-").Groups.ToArray<System.Text.RegularExpressions.Group‌​>(), и Regex.Match("aa", @"key : (.+?)-").Groups.ToArray<KeyValuePair<string,System.Text.Regu‌​larExpressions.Group‌​>>() прекрасно компилируются...

Alexei Levenkov 22.02.2023 23:55

Хорошо бы знать, какие ошибки выдает компилятор. Обычно они помогают понять, почему он отказывается что-то компилировать. Вероятно, это из-за того, что GroupCollection реализует как IEnumerable<Group>, так и IEnumerable<KeyValuePair<string,System.Text.RegularExpressio‌​ns.Group>>, но ошибка компилятора действительно прояснила бы это.

moreON 23.02.2023 00:00

@AlexeiLevenkov добавил скриншот ошибки. По крайней мере для меня это странно...

meJustAndrew 23.02.2023 00:02

@moreON то же самое, пожалуйста, проверьте скриншот. Так вы говорите, что об этом нужно сообщить в Microsoft?

meJustAndrew 23.02.2023 00:03
Калькулятор CGPA 12 для семестра
Калькулятор CGPA 12 для семестра
Чтобы запустить этот код и рассчитать CGPA, необходимо сохранить код как HTML-файл, а затем открыть его в веб-браузере. Для этого выполните следующие...
Как собрать/развернуть часть вашего приложения Angular
Как собрать/развернуть часть вашего приложения Angular
Вам когда-нибудь требовалось собрать/развернуть только часть вашего приложения Angular или, возможно, скрыть некоторые маршруты в определенных средах?
Запуск PHP на IIS без использования программы установки веб-платформы
Запуск PHP на IIS без использования программы установки веб-платформы
Установщик веб-платформы, предлагаемый компанией Microsoft, перестанет работать 31 декабря 2022 года. Его закрытие привело к тому, что мы не можем...
Оптимизация React Context шаг за шагом в 4 примерах
Оптимизация React Context шаг за шагом в 4 примерах
При использовании компонентов React в сочетании с Context вы можете оптимизировать рендеринг, обернув ваш компонент React в React.memo сразу после...
Библиотека для работы с мороженым
Библиотека для работы с мороженым
Лично я попрощался с операторами print() в python. Без шуток.
Настройка шаблона Metronic с помощью Webpack и Gulp
Настройка шаблона Metronic с помощью Webpack и Gulp
Я пишу эту статью, чтобы поделиться тем, как настроить макет Metronic с помощью Sass, поскольку Metronic предоставляет так много документации, и они...
2
4
57
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Проблема в том, что GroupCollection реализует две разные версии интерфейса IEnumerable<>:

public class GroupCollection : 
System.Collections.Generic.ICollection<System.Text.RegularExpressions.Group>,
System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string,System.Text.RegularExpressions.Group>>,
System.Collections.Generic.IEnumerable<System.Text.RegularExpressions.Group>, 
System.Collections.Generic.IList<System.Text.RegularExpressions.Group>, 
System.Collections.Generic.IReadOnlyCollection<System.Collections.Generic.KeyValuePair<string,System.Text.RegularExpressions.Group>>, 
System.Collections.Generic.IReadOnlyCollection<System.Text.RegularExpressions.Group>, 
System.Collections.Generic.IReadOnlyDictionary<string,System.Text.RegularExpressions.Group>, 
System.Collections.Generic.IReadOnlyList<System.Text.RegularExpressions.Group>, 
System.Collections.IList

Компилятор не знает, какой универсальный тип передать в метод Enumerable.Select<>(): должен ли он использовать Group или KeyValuePair<string, Group>?

Вы можете увидеть такое же поведение из следующего кода:

new Foo().Select(i => i);

public class Foo : IEnumerable<int>, IEnumerable<string>
{
    IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw new NotImplementedException();
    IEnumerator<string> IEnumerable<string>.GetEnumerator() => throw new NotImplementedException();
    IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
}

Приводя его явно, вы устраняете эту двусмысленность. Чуть менее многословная (но менее эффективная) альтернатива — вызов .Cast<Group>()

var bar = groups.Cast<Group>().Select(x => x.Value).ToArray();

Или вы можете явно указать общие параметры для метода:

var bar = groups.Select<Group, string>(x => x.Value).ToArray();

Или укажите тип параметра в делегате, который вы передаете:

var bar = groups.Select((Group x) => x.Value).ToArray();

КРЫСЫ. Ты подтолкнул меня на это! Это, насколько мне известно, правильный ответ.

Josh Heaps 23.02.2023 00:06

Должен ли он просто выбрать один, или это было бы небезопасным поведением?

meJustAndrew 23.02.2023 00:06

@meJustAndrew, когда есть двусмысленность, разработчик должен удалить ее, явно указав, какой из них использовать.

Josh Heaps 23.02.2023 00:07

Другой способ устранить неоднозначность методов Linq — указать тип для параметров выражения. например new Foo().Select( (string i) => "" );

moreON 23.02.2023 00:11

Хороший отзыв, @moreON! Я включил это в свой ответ.

StriplingWarrior 23.02.2023 00:14

GroupCollection реализует два IEnumerable<T> интерфейса — IEnumerable<Group> и IEnumerable<KeyValuePair<string, Group>>, поэтому компилятор не может определить, какой из них использовать для Select (и других Enumerable методов расширения).

Другой подход — указать тип в labmda:

var bar = groups.Select((Group x) => x.Value).ToArray();

Или укажите общие параметры явно:

var bar = groups.Select<Group, string>(x => x.Value).ToArray();

Или используя OfType/Cast:

var bar = groups.OfType<Group>().Select(x => x.Value).ToArray();

Хотя последний теоретически может сломаться, если реализация внутреннего счетчика будет изменена.

OfType имеет поведение фильтрации, из-за чего мне неудобно использовать его для кастинга.

Theodor Zoulias 23.02.2023 07:33

Другие вопросы по теме