Мой вопрос об именах, дизайне и вариантах реализации. Я вижу, что я собираюсь в двух разных направлениях: как решить проблему, и мне интересно узнать, как справиться с проблемой могут другие люди, которые могли столкнуться с подобными проблемами. Это часть эстетики, функция части.Переопределить ToString или предоставить метод расширения имени не для ToString для интерфейса?
Немного фона для кода ... Я создал тип, называемый ISlice<T>
, который предоставляет ссылку в раздел источника элементов, который может быть коллекцией (например, массивом, списком) или строкой. Основная поддержка исходит из нескольких классов реализации, которые поддерживают быструю индексацию с использованием маркеров Begin и End для среза, чтобы получить элемент из исходного источника. Цель состоит в том, чтобы обеспечить возможности среза, аналогичные тому, что предоставляет язык Go при использовании индексации стиля Python (т. Е. Поддерживаются как положительные, так и отрицательные индексы).
Чтобы сделать создание фрагментов (экземпляров ISlice<T>
) проще и более «бегло», я создал набор методов расширения. Например:
static public ISlice<T> Slice<T>(this IList<T> source, int begin, int end)
{
return new ListSlice<T>(source, begin, end);
}
static public ISlice<char> Slice(this string source, int begin, int end)
{
return new StringSlice(source, begin, end);
}
Есть другие, такие, как предоставление по желанию начать/конечные параметры, но выше будет достаточно для того, где я собираюсь с этим.
Эти подпрограммы хорошо работают и позволяют легко нарезать коллекцию или строку. Мне также нужен способ взять срез и создать его копию как массив, список или строку. Вот где вещи становятся «интересными». Первоначально я думал, что мне нужно будет создать методы расширения ToArray, ToList, но потом вспомнил, что варианты LINQ выполняют оптимизацию, если ваша коллекция реализует ICollection<T>
. В моем случае, ISlice<T>
, наследует от него, хотя, по большому счету, к моему огорчению, поскольку мне не нравится бросать NotSupportedExceptions из таких методов, как Add. Несмотря ни на что, я получаю их бесплатно. Отлично.
Как преобразовать обратно в строку, поскольку нет встроенной поддержки для преобразования IEnumerable<char>
обратно в строку? Ближайшая вещь, которую я нашел, является одной из строк. Перегрузка Concat, но она не будет обрабатывать символы как можно эффективнее. Столь же важным с точки зрения дизайна является то, что он не выпрыгивает, как рутина «преобразования».
Первой мыслью было создать метод расширения ToString, но это не работает, поскольку ToString - это метод экземпляра, который означает, что он перехватывает методы расширения и никогда не будет вызван. Я мог бы переопределить ToString, но поведение было бы непоследовательным, так как ListSlice<T>
понадобится для специального случая его ToString для времен, где T является символом. Мне это не нравится, поскольку ToString даст что-то полезное, когда параметр типа является символом, но имя класса в других случаях. Кроме того, если в будущем будут созданы другие типы срезов, мне нужно будет создать общий базовый класс для обеспечения того же поведения, или каждый класс должен будет выполнить эту же проверку. Метод расширения на интерфейсе будет обрабатывать гораздо более элегантно.
Метод расширения приводит меня к вопросу об именовании. Очевидным является использование ToString, но, как было сказано ранее, это запрещено. Я мог бы назвать это чем-то другим, но что? ToNewString? NewString? CreateString? Что-то в методе To-family позволяло ему входить в подпрограммы ToArray/ToList, но ToNewString выступает как «нечетный», если смотреть в редакторе intellisense и в коде. NewString/CreateString не так понятны, как вам следовало бы знать, чтобы их искать. Он не соответствует шаблону «метод преобразования», который предоставляет метод To-family.
Перейти с переопределением ToString и принять противоречивое поведение, жестко закодированное в реализацию ListSlice<T>
и другие реализации? Идите с более гибким, но потенциально более слабо названным маршрутом метода расширения? Есть ли третий вариант, который я не рассматривал?
Моя кишка говорит мне идти с ToString, несмотря на мои оговорки, хотя это также пришло мне в голову ... Вы даже подумали бы о том, что ToString дает полезный результат для коллекции/перечисляемого типа? Разве это нарушит принцип наименьшего удивления?
Update
Большинство реализаций операций нарезки предоставить копию, хотя подмножество, данных из любого источника использовалась для среза. Это вполне приемлемо в большинстве случаев использования и выходит за чистый API, поскольку вы можете просто вернуть тот же тип данных обратно. Если вы вырезаете список, вы возвращаете список, содержащий только элементы в диапазоне, указанном в срезе. Если вы нарезаете строку, вы возвращаете строку. И так далее.
Режущие операции, которые я описываю выше, решают проблему при работе с ограничениями, которые делают это поведение нежелательным. Например, если вы работаете с большими наборами данных, операции среза приведут к ненужным дополнительным распределениям памяти, не говоря уже о влиянии производительности копирования данных. Это особенно актуально, если срезы будут обрабатывать их до получения окончательных результатов. Таким образом, цель реализации среза состоит в том, чтобы иметь ссылки в более крупные наборы данных, чтобы избежать ненужных копий информации, пока это не станет выгодным для этого.
Уловка заключается в том, что в конце обработки возникает желание превратить обработанные данные на основе среза в более дружественный тип API и .NET, например списки, массивы и строки. Это упрощает передачу данных в другие API. Он также позволяет отбрасывать срезы, таким образом, также большие данные устанавливают срезы, на которые делается ссылка.
FYI, добавляя символы обратного тика, позволит вам говорить такие вещи, как 'IEnumerable' –
StriplingWarrior
Спасибо за то, что на него набросились. Пропустил этот связанный ввод кода. –