Всё классно, но несколько типов/методов не дотягивают до общей (довольно высокой) планки.
Может, их в Experimental пока?
1. DisjointSetsBase выглядит как заготовка для чего-то большего.
С точки зрения незнакомого с матчастью клиента код выглядит как один большой WTF. Ну вот навскидку
* базовый класс не абстрактный
* как часть контракта торчит T (в идеале переименовать в TNode), который в публичном API недоступен,
* никаких проверок индексов
но это чисто косвенные признаки, главная проблема в том, что никаких реальных сценариев использования при дизайне API не использовалось.
Ну, или эти сценарии настолько экзотичные, что из API их не восстановишь.
2. EnumerableExtensions — AsList, AsArray, ToStrings. По сравнению с остальными все три выглядят _очень_ спорно.
Они нам точно нужны?
3. StringExtensions.Length()
public static int Length([CanBeNull] this string str) => str?.Length ?? 0;
Я бы убрал. Ну, или переименовать в TryGetLength тогда уж.
4. ParallelExtensions.RunInParallel + ParallelQueue. Сам код ок, но чем оно лучше Parallel.For/Foreach?
Нужен свой пул — надо свой таск шедулер делать. Иначе будет побег из курятника на первом же await.
5. ReaderWriterLockSlimExtensions — надо наследовать от CriticalFinalizerObject + освобождать в финалайзере. Иначе первый же залетевший дятел Thread.Abort() очень больно всё порушит.
UPD 6. XNodeExtensions — Required/Optional переименовать в стандартные Get/TryGet/XxxOrDefault.
Все 6 точно делать только после обсуждения, тут на своей правоте не настаиваю
Здравствуйте, Sinix, Вы писали:
S>Продолжаю смотреть код в CodeJam.
S>Всё классно, но несколько типов/методов не дотягивают до общей (довольно высокой) планки. S> Может, их в Experimental пока?
S>1. DisjointSetsBase выглядит как заготовка для чего-то большего. S>С точки зрения незнакомого с матчастью клиента код выглядит как один большой WTF.
Соглашусь, интерфейс класса не слишком очевидный. Если у кого есть идеи, как сделать лучше, то готов выслушать.
S>Ну вот навскидку S>* базовый класс не абстрактный
А зачем ему быть абстрактным? Абстрактных методов у него нет. Создать его не выйдет, ибо protected .ctor
S>* как часть контракта торчит T (в идеале переименовать в TNode), который в публичном API недоступен,
Зато доступен в protected. Используется, чтобы лишние касты не городить потом.
S>* никаких проверок индексов
Это есть, да.
S>но это чисто косвенные признаки, главная проблема в том, что никаких реальных сценариев использования при дизайне API не использовалось. S>Ну, или эти сценарии настолько экзотичные, что из API их не восстановишь.
Использовались. Основной сценарий был такой:
1) Сконструировать из пачки элементов.
2) Объединить некоторые из них.
3) Для каждого из элементов определить, в какое объединение он попал.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Lexey, Вы писали:
L>>Я выше написал основной use case, который мне встречался.
AVK>Там маловато информации — какую задачу ты решал в принципе.
Например, все то же объединение кластеров на плоскости (про которое я Sinix'у в теме про LowerBound написал):
На входе список кластеров, на выходе нужно получить новый набор, в котором каждая группа пересекающихся кластеров заменяется одним большим кластером.
Сначала все кластеры загоняются в DisjointSets (каждый кластер — отдельное множество, непересекающееся с остальными). Далее проверяются пересечения. Если есть пересечение, то 2 множества объединяются в одно.
В конце пробегаем по всем элементам в disjointsets, групируя все кластеры с одинаковыми id итоговых непересекающихся множеств (тут, в принципе, мог бы пригодиться итератор по итоговым множествам, но не очень понятно, как его реализовать лучше, чем все тем же полным сканом всех элементов).
Здравствуйте, Sinix, Вы писали:
S>4. ParallelExtensions.RunInParallel + ParallelQueue. Сам код ок, но чем оно лучше Parallel.For/Foreach?
Это побочный эффект реализованного в одном из методов Provider/Consumer паттерна. Отличается от Foreach с ограничителем MaxDegreeOfParallelism предсказуемостью. Т.е. никаких лишних процессов по непонятным причинам в самый неожиданный момент запущено не будет.
S>Нужен свой пул — надо свой таск шедулер делать. Иначе будет побег из курятника на первом же await.
Свой пул не нужен. Это аналог LonRunning, у которого с await такие же проблемы, т.е. для сценариев работы с ним оно не предназначено.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
S>>4. ParallelExtensions.RunInParallel + ParallelQueue. Сам код ок, но чем оно лучше Parallel.For/Foreach? IT>Это побочный эффект реализованного в одном из методов Provider/Consumer паттерна. Отличается от Foreach с ограничителем MaxDegreeOfParallelism предсказуемостью. Т.е. никаких лишних процессов по непонятным причинам в самый неожиданный момент запущено не будет.
Ага, дошло зачем
Вещь хорошая, надо брать
Как предложение — может, задокументировать назначение в xml-комментарии к методу?
И ещё предложение: добавить Async-варианты, чтоб не блокировать вызывающий поток. Как минимум, неблокирующий аналог ParallelQueue.WaitAll() я бы добавил.