Как стать автором
Обновить

Комментарии 12

1. Где тесты?
2. Где пакет NuGet?
3. Почему документация на русском?
4. Почему IReadOnlyFiniteSet в корне?
5. Названия классов дерзкие, да.
Спасибо за указание на возможные проблемы, поправил «дерзкие» имена классов. Collection -> ReadOnlyCollection, FiniteSet -> ReadOnlyFiniteSet, List -> ReadOnlyList. Теперь выглядит немного сложнее: List.Empty<>() будет ReadOnlyList.Empty<>() зато меньше вероятность коллизий.
IReadOnlyFiniteSet не имеет прямого отношения к этой библиотеке, поэтому в корне. неясно делать ли его частью nuget-пакета или отдельно. вариант nuget-пакета с ним в комплекте тут www.nuget.org/packages/CollectionLinq

тесты и nuspec есть, добавлю в проект сегодня попозже
добавил в проект, как обещал, тесты и nuspec
>> Все входные и выходные коллекции LINQ-операций имеют базовый тип IEnumerable<>, исходя из ограниченных возможностей которого, многие операции подразумевают лишние затраты: полный последовательный перебор или даже создание промежуточных копий входных коллекций.

На самом деле, в LINQ очень много где встречаются проверки типа входящего IEnumerable, чтобы реализовать операцию более эффективно, если это ICollection или там IList. Например, Enumerable.Count просто вернет ICollection.Count, если он доступен на данном объекте.

Аналогично с промежуточными результатами. Например, Where возвращает IEnumerable, но если его снова передать в Where, то там есть проверка на этот конкретный тип, и она просто добавит дополнительное условие напрямую.
ну я так и написал:
В «LINQ к объектам» уже реализована подобная внутренняя оптимизация: многие методы первым делом проверяют реализацию некоторых интерфейсов входной коллекцией, и используют их для более эффективного выполнения действий.

Но, всё таки, даже «старые» полные интерфейсы используются в LINQ не всегда. Например, в методе Reverse интерфейс IList<> не проверяется и всегда создаётся полная копия всей коллекции. А уж возвращаемая коллекция практически никогда не реализует никаких интерфейсов кроме базового IEnumerable<>, в связи с чем следующий метод в цепочке опять будет всё перебирать и создавать копию.
Для сравнения, в моей CollecitonsLinq для коллекции типа IReadOnlyList<> в методе Reverse() будет возвращён непосредственный декоратор типа IReadOnlyList<> без перебора и копирования.

А про операцию Where я отметил, что в ней улучшать нечего и предлагаю использовать такую, как есть.
Значительно сокращено количество перегрузок методов за счёт повсеместного использования опциональных параметров (появившихся на год позже LINQ).

Я надеюсь, вы знаете, как именно в C# реализованы значения для необязательных параметров, и понимаете, во что это выльется для кода, который использует вашу библиотеку.

if (source == null)
{
    throw new ArgumentNullException ("source");
}
Contract.EndContractBlock ();
(и так в каждом методе) Почему уж тогда не Contract.Requires<ArgumentNullException>(source != null)?

И почему вы не используете стандартные LINQ-реализации внутри ваших классов-оберток (называть их декораторами я бы не стал)?
Про опциональные параметры я в курсе. И проштудировал множество рекомендаций и обсуждений. Авторитетные для меня люди утверждают, что допустимо использовать совершенно очевидное значение (null для ссылочных типов), которое не может измениться ни в какой мыслимой ситуации.

Выбор между «if () throw» и Contract.Requires() сделан согласно рекомендациям официального руководства по Code Contracts (см. раздел 5 Usage Guidelines). Это единственный вариант не требующий установки и настройки отдельного инструментария и в тоже время позволяющий создавать отдельные конфигурации прокта и использовать в них контракты для статического анализа.

Не вижу ни одного места где мог бы использовать что-то готовое из LINQ. Судя по его исходникам мог бы использовать кое что, но оно помечено как internal.
Про опциональные параметры я в курсе. И проштудировал множество рекомендаций и обсуждений. Авторитетные для меня люди утверждают, что допустимо использовать совершенно очевидное значение (null для ссылочных типов), которое не может измениться ни в какой мыслимой ситуации.

Что вы будете делать в ситуации, когда необязательный параметр будет убран? Что вы будете делать в ситуации, когда добавится новый необязательный параметр?

Это единственный вариант не требующий установки и настройки отдельного инструментария и в тоже время позволяющий создавать отдельные конфигурации прокта и использовать в них контракты для статического анализа.

В чем проблема настроить отдельный инструментарий?

(а статический анализ вы делаете без отдельного инструментария?)

Не вижу ни одного места где мог бы использовать что-то готовое из LINQ.

private class TakeReadOnlyCollection<TSource> : IReadOnlyCollection<TSource>
{
    private readonly IReadOnlyCollection<TSource> _source;
    private readonly int _сount;
    public IEnumerator<TSource> GetEnumerator ()
    {
        var count = _count;
        foreach (var item in _source)
        {
            yield return item;
            if (--count == 0)
            {
                break;
            }
        }
    }
}


Что мешает сделать return _source.AsEnumerable().Take(_count).GetEnumerator()?
1. API фиксирванный (диктуется LINQ), поэтому никто удалять или добавлять параметры не будет.
2. Про установку и настройку инструментов. Я считаю, что не имею права заставлять людей это делать просто чтобы скомпилировать мой проект.
3. Согласен, в нескольких аналогичных местах можно съэкономить пяток строк кода, считаю это неприпинципиально. Сделаю в свободное время.
API фиксирванный (диктуется LINQ), поэтому никто удалять или добавлять параметры не будет.

Мне бы ваш оптимизм.

Я считаю, что не имею права заставлять людей это делать просто чтобы скомпилировать мой проект.

Почему? Ваш проект разрабатывается так, как вам удобно. Людей интересует результирующий nuget — вот у него должен быть минимум зависимостей. А как вы проект собираете — особенно если это можно сделать, просто забрав версию — никого не волнует.

Согласен, в нескольких аналогичных местах можно съэкономить пяток строк кода, считаю это неприпинципиально.

Дело не только в строках кода, но и в количестве создаваемых объектов. Ну и читаемость, конечно.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории