Обновить
58

Пользователь

51
Подписчики
Отправить сообщение
Все документы реализуют следующий интерфейс (ADocument) доступный для использования в CoreViewModel
public abstract Task<bool> Load();
public abstract Task<bool> Save();
public abstract Task<bool> SaveAs();
public abstract Task<bool> Close();

Подразумевается, что в случае успешного выполнения возвращается true, иначе false.

Когда основная вью-модель вызывает у дочерней один из этих методов, то это выглядит, словно руководитель выдаёт подчинённому команду что-то сделать, ставит задачу.

Это не забота руководителя, каким образом подчинённый будет выполнять задание и обрабатывать возникающие трудности (исключения), важен лишь конечный результат и то, что руководитель выполнил свою работу по постановке задачи. Классическое разделение ответственности.
Ох, не знаю, какой у вас проект, но обычно никто не держит в памяти по сто тысяч объектов за редкими исключениями. В интерпрайз-решениях, как правило, используют виртуализацию на уровне данных и/или визуального интерфейса.

То, о чём вы говорите, это сценарий для высоконагруженного сервера, кэширующего данные в памяти, или же очень специфического клиента. А для исключений нужны и исключительные решения.

Поэтому не вижу смысла отказываться от паттерна общего назначения, из-за каких-то маловероятных падений производительноти. Если вдруг начнёт что-то ощутимо замедляться из-за вызовов 'With', то не вижу проблемы их убрать, благо, код не потребует огромной реструктуризации.
Раз уж язык позволяет стандартными средствами написать 'i is 0', то почему бы и нет? Мне, например, больше нравится писать '==' в контексте арифметических выражений, а в логических использовать 'is', хотя они и взаимозаменяемы в некоторых случаях.

И да, интуитивно я предполагаю, что компилятор умный и развернёт 'i is 0' в 'i == 0', но он поступает иначе. Конечно, 20% не такой уж большой выигрыш в производительности, но уже ощутимый, и, стоит отметить, методы-расширения поддерживают не только константные выражения.

Кроме того, следующая перегрузка позволяет указывать 'fallbackValue', что позволяет писать более гибкую логику

public static TX Put<T, TX>(this T o, TX x) => x;

public static bool Is<T>(this object o,
  out T x, T fallbackValue = default(T)) =>
    (x = (o is T).To(out var b) ? (T) o : fallbackValue).Put(b);


if (model.Is(out AnyModel m, AnyModel.Default))
    Console.WriteLine($"Custom AnyModel {m}");
else Console.WriteLine($"Default AnyModel {m}");

Поэтому возникает закономерный вопрос, раз методы-расширения более обобщённые и не уступают (а иногда и выигрывают) по производительнотсти, то зачем мне использовать встроенный, но весьма ограниченный синтаксический сахар?
В статье рассмотрен аналогичный сценарий — пару раз встретишь на практике, научишься и путаница исчезнет.
Ошибки загрузки из файла обрабатываются в самих дочерних вью-моделях.

На момет окончания метода 'CoreViewModel.Expose' важно выполнить лишь Expose у коллекции документов, а загрузкой данных из файла заведует сам документ.
Как говорится: «Любое категоричное суждение ошибочно, даже это». Поэтому не стоит воспринимать мои слова как абсолютную истину :)

Здорово, что вы критикуете и обдумываете аргументы, не принимая их сразу на веру, ведь я тоже могу ошибаться, заблуждаться и быть слишком субъективным.
Знаете, за немало лет коммерческого программирования мне трудно вспомнить даже пару случаев, когда бы я имел дело с сотнями тысяч и уж тем более с миллионами объектов. Разве что в тестовых целях проверял производительность каких-то методов на больших массивах.

Обычно в таких сценариях, где много данных и важна высокая скороть их обработки, уже пишут код на более низкоуровневых языках.
Здесь разное поведение.

Думаю, так будет лучше видна разница в логике
Documents.CollectionChangeCompleted += (sender, args)
{
    var document = args.NewItems?
        .Cast<ADocument>().LastOrDefault();
    if (document != null) ActiveDocument = document;
}

По задумке не нужно менять активный документ, если, например, пользователь закрыл другой неактивный и сработало событие 'CollectionChangeCompleted'.
Без ожидания параллельно.
Спасибо! Но когда речь идёт о стомиллионных долях секунды, то разница в пять и даже сто раз просто не ощутима на практике, за исключением очень редких случаев, где важна производительность или очень много данных.

Поэтому для себя не вижу существенных причин отказываться от 'With'.

Думаю, каждый разработчик сам сможет определить область применения рассмотренным приёмам программирования. )

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

В любом случае, иногда полезно взглянуть даже на хорошо знакомые вещи с другой стороны. Своего рода разминка для ума. :)
По многим пунктам с вами согласен.

Проект Ace — это набор базовых библиотек, которые я использую в качестве основы для других своих проектов. Своего рода экстракт моих наработок и знаний за годы активного программирования.

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

Возможно, есть люди, которым такое тоже интересно, а статья послужит поводом для переосмысления даже таких фундаментальных вещей, как присваивание и передача параметров в методы.
Смотрите сами, что вам больше по душе. ))
Всё просто — в первом цикле инициализируем вью-модели документов, а во втором асинхронно загружаем в каждую информацию из файлов.

Если вы хотите подковырнуть меня тем, что я дважды прохожусь по коллекции, то здесь это никаких проблем не вызывает.

Можете даже скомпилировать проект и убедиться, что всё работает вполне себе живо. :)
Скорее: «Смотри, ты тоже так можешь!»

Как уже говорил ранее, мне близок дух изобретательства и свободы в программировании. Но каждому человеку своё — кому-то больше по душе традиционные подходы.

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

Буду рад распрощаться со своими заблуждениями насчёт вызова пустых методов.
Если для вас это выглядит «хламом», то не пользуйтесь. )

Насчёт совмещения — это демонстрационный пример, задача которого показать различные сценарии использования. Конечно, я бы мог разбить его на более мелкие части, но в собранном виде мне нравится больше.

По ссылке можно увидеть пример стиля, в котором я предпочитаю писать код.
Вы пробовали когда-нибудь замерить, скольколько же стоит вызов пустого метода?
var w = new Stopwatch();
w.Start();
for (int i = 0; i < 100000000; i++)
{
	w.With(w, i);
}
w.Stop();
System.Console.WriteLine(w.ElapsedMilliseconds);

На моём не самом передовом компьютере 100 000 000 вызовов заняли около секунды на релизном билде. То есть вызов 'With' занимает 1/100 000 000 (одну стомиллионную секунды)!

Не знаю, как вам, но для моих задач этого хватит с лихвой.

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

Так что не стоит сгущать краски над 'With', вызов этот занимает порядка одной стомиллионной секунды на среднем компьютере. Уверен, что даже для мобильных устройств эта цифра будет вполне адекватная.
Скажу так… насчёт expression-bodied стиля:

• провоцирует оформлять код мелкими методами с раздельной отвественностью
• меньше скобок и лишних слов вроде return
• эстетически красиво и лаконично
• развивает чувство прекрасного
• учит писать чистый и общённый код

И лично для меня последние пункты самые важные. :)
Если бы не эта математическая красота, то давно бы уже забросил программирование!
Что вы подразумеваете под сбросом состояния? Насколько я понимаю, локальные переменные всегда остаются в стеке (во многом это и вызывает stack overflow при крайне глубоком рекурсивном вызове методов). Зачем их куда-то ещё сбрасывать, чтобы потом восстанавливать?

Думаю, что современные языки отлично оптимизированы для работы со стеком вызовов и поощеряют разделение кода на маленькие методы.

Моё понимание интуитивно, поэтому могу ошибаться, поправьте, если что не так. :)

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность