Наследовать IEnumerable от последствий объекта

Я опубликовал ответ на этот вопрос, включая очень короткую тираду в конце о том, как String.Split() должен принимать IEnumerable‹string > вместо строки[].

Это заставило меня задуматься. Что, если базовый класс Object, от которого наследуется все остальное, предоставил реализацию по умолчанию для IEnumerable, так что все теперь возвращает Enumerator только для одного элемента (самого себя) - если только он не переопределен, чтобы делать что-то еще, например, с классами коллекций.

Идея состоит в том, что тогда, если бы такие методы, как String.Split(), принимали IEnumerable, а не массив, я мог бы передать одну строку функции, и она просто работала бы, вместо того, чтобы много заниматься созданием массива разделителей.

Я уверен, что есть множество причин не делать этого, не последняя из которых заключается в том, что если бы все реализовало IEnumerable, то несколько классов, реализация которых отклоняется от значения по умолчанию, могли бы вести себя иначе, чем вы ожидаете в определенных сценариях. Но я все равно думал, что это будет забавное упражнение: какие еще могут быть последствия?


person Joel Coehoorn    schedule 30.09.2008    source источник
comment
Интересно, стоит ли мне разделить ответы...   -  person MagicKat    schedule 01.10.2008


Ответы (2)


Думали ли вы об использовании вспомогательного объекта и реализации Split для класса IEnumerable?

Однажды я сделал GetDescription для класса Enum, чтобы легко получить DescriptionAttribute. Это работает удивительно хорошо.

person Leahn Novash    schedule 30.09.2008

оператор индекса ([]) не является частью контракта IEnumerable‹T› После просмотра кода в рефлекторе код активно использует оператор индекса, который всегда является частью Array.

Ну, проще говоря, у Array всегда будет перечислитель.

Идея состоит в том, что тогда, если бы такие методы, как String.Split(), принимали IEnumerable, а не массив, я мог бы передать одну строку функции, и она просто работала бы, вместо того, чтобы много заниматься созданием массива разделителей.

Это неправда, строка наследует IEnumerable‹char›. И у вас нет общей дисперсии, поэтому вы не можете привести IEnumerable‹char› к IEnumerable‹string›. Вы получите версии IEnumerable‹char› разделения, а не требуемую строку.

person MagicKat    schedule 30.09.2008
comment
Однако я бы предпочел, чтобы string.Join принимал IEnumerable, а не string[] в его нынешнем виде. - person Jeff Yates; 01.10.2008
comment
Это деталь реализации. Если IEnumerable поддерживает оператор индекса (чего нет), я уверен, что он будет использоваться. - person MagicKat; 01.10.2008
comment
@Jeff Yates: К сожалению, IEnumerable на самом деле не дает гарантии, что несколько итераций дадут идентичные данные. Чтобы String.Join работал, он должен сделать один проход по списку, чтобы определить общую длину всех строк, а затем второй проход, чтобы фактически соединить их вместе. Если бы два прохода через IEnumerable возвращали строки разной длины, это могло бы привести к ошибочной операции соединения. - person supercat; 05.06.2011
comment
@supercat: ответственность за эту гарантию лежит не на интерфейсе, а на конкретном экземпляре типа, который предоставляет интерфейс. Кроме того, нет причин, по которым string.Join должен выполнять два прохода. Используя StringBuilder и небольшую обрезку в конце, все это можно сделать за один проход. - person Jeff Yates; 05.06.2011
comment
@Jeff Yates: Если строка большая, StringBuilder намного лучше, чем использование множества конкатенаций отдельных строк, но использование StringBuilder для построения строки размером 300 КБ приведет к созданию 896 КБ временного мусора в куче больших объектов. Предварительный подсчет необходимого пространства устранит дополнительные выделения и предотвратит любую фрагментацию, которую они могут вызвать. - person supercat; 05.06.2011
comment
@supercat: Это может быть так, но по-прежнему нет необходимости дважды анализировать IEnumerable. Вы можете проанализировать один раз и кэшировать результат. Я все еще не думаю, что ваша первоначальная точка зрения верна. - person Jeff Yates; 06.06.2011
comment
@Jeff Yates: В зависимости от базового типа IEnumerable может быть быстрее всего преобразовать его в массив, а затем использовать String.Join для массива, или прочитать каждый элемент один раз и добавить его в StringBuilder, или прочитать каждый пункт дважды. Если IEnumerator просто извлекает элементы из массива, двухпроходный подход будет лучшим. Если исходный файл представляет собой файл с несколькими очень длинными строками, лучше всего читать массив. Если это файл с большим количеством строк по пару символов в каждой, лучше всего подойдет подход StringBuilder. - person supercat; 06.06.2011
comment
@Jeff Yates: Возможно, лучшим подходом в целом было бы использование предварительно выделенного массива строк, но метод соединения должен использовать StringBuilder для сборки групп строк на общую сумму 80 КБ или меньше. Это повлечет за собой лишь несколько выделений, и ни одно из них не превысит 85 КБ. - person supercat; 06.06.2011