Как вариант, можно использовать Factory. В сигнатуру фабричного метода поместить все зависимости для самой модели, а утилитарные зависимости попросить в саму фабрику и передать создаваемому объекту:
public class ViewModelFactory : IViewModelFactory
{
private readonly IEventAggregator _aggregator;
private readonly IProgress _progress;
private readonly IPromptCreator _promptCreator;
public ViewModelFactory(IEventAggregator aggregator, IProgress progress, IPromptCreator promptCreator)
{
_aggregator = aggregator;
_progress = progress;
_promptCreator = promptCreator;
}
public ViewModel CreateViewModel(IPaymentSystem paymentSystem, IRulesValidator rulesValidator)
=> new ViewModel(_aggregator, _progress, _promptCreator, paymentSystem, rulesValidator);
}
Не буду утверждать, что это более элегантно, чем Property Injection.
По поводу исключений ещё один интересный вопрос — производительность. try-catch вместо if — это плохо не только потому, что ухудшает читабельность кода, а ещё и потому, что это просто медленнее.
По поводу полностью асинхронных методов:
Мое мнение — особо смысла в этом нет. Visual Studio справедливо подмечает, что async метод, не использующий await, будет выполняться последовательно (синхронно). А таких методов большинство.
По сути вся соль не в async методах, а в том, что они возвращают Task. Хочешь — жди результат сразу, хочешь — запусти еще один метод параллельно и дождись, пока отработает и то и то.
А вызвать любой метод асинхронно, в принципе, не так и сложно — нужно вызов просто пережать в Task.Run.
Да, в целом идея такая.
При этом, как выше упоминал kekekeks, TaskCompletionSource можно использовать и для создания искуственных тасков, не связанных с чем-то асинхронным, и await'ить их.
Да, всё именно так. Собственно, цель паттерна async/await — позволить писать асинхронный код в привычном, последовательном стиле: весь код после await неявно становится одним большим колбэком. Плюс подхода в том, что вызывающий поток работает до первого await, а после этого возвращается в пул потоков и может быть использован повторно (на самом деле всё несколько сложнее, тут ещё много магии с SynchronizationContext, но в принципе как-то так). Но при этом никто не запрещает завести столько Task'ов, сколько нужно, и собрать их в одном месте при помощи Task.WhenAll или Task.WhenAny.
Не буду утверждать, что это более элегантно, чем Property Injection.
get-only свойства ведут себя точно так же, как readonly поля.
Мое мнение — особо смысла в этом нет. Visual Studio справедливо подмечает, что async метод, не использующий await, будет выполняться последовательно (синхронно). А таких методов большинство.
По сути вся соль не в async методах, а в том, что они возвращают Task. Хочешь — жди результат сразу, хочешь — запусти еще один метод параллельно и дождись, пока отработает и то и то.
А вызвать любой метод асинхронно, в принципе, не так и сложно — нужно вызов просто пережать в Task.Run.
При этом, как выше упоминал kekekeks, TaskCompletionSource можно использовать и для создания искуственных тасков, не связанных с чем-то асинхронным, и await'ить их.