Предположим, что у меня есть интерфейсный метод, реализованный как
public void DoSomething(User user)
{
if (user.Gold > 1000) ChatManager.Send(user, "You are rich: " + user.Gold);
}
Через некоторое время я понимаю, что хочу изменить его:
public async Task DoSomething(User user)
{
if (user.Gold > 1000) ChatManager.Send(user, "You are rich: " + user.Gold);
if (!user.HasReward)
{
using(var dbConnection = await DbPool.OpenConnectionAsync())
{
await dbConnection.Update(user, u =>
{
u.HasReward = true;
u.Gold += 1000;
});
}
}
}
Я меняю сигнатуру метода в интерфейсе. Но вызывающие методы были синхронными, и я должен сделать не только их async, но и все дерево вызовов async.
Пример:
void A()
{
_peer.SendResponse("Ping: " + _x.B());
}
double X.B()
{
return _someCollection.Where(item => y.C(item)).Average();
}
bool Y.C(int item)
{
// ...
_z.DoSomething();
return _state.IsCorrect;
}
следует изменить на
async void AAsync()
{
_peer.SendResponse("Ping: " + await _x.BAsync());
}
async Task<double> X.BAsync()
{
// await thing breaks LINQ!
var els = new List<int>();
foreach (var el in _someCollection)
{
if (await y.CAsync(item)) els.Add(el);
}
return _els.Average();
}
async Task<bool> Y.CAsync(int item)
{
// ...
await _z.DoSomething();
return _state.IsCorrect;
}
Затронутое дерево вызовов может быть очень большим (многие системы и интерфейсы), поэтому это изменение трудно сделать.
Также, когда первый метод A
вызывается из метода интерфейса, такого как IDisposable.Dispose
- я не могу сделать его асинхронным.
Другой пример: представьте, что несколько вызовов на A
хранились в качестве делегатов. Раньше они вызывались только с _combinedDelegate.Invoke()
, но теперь я должен пройти через GetInvocationList()
и await
для каждого элемента.
О, и рассмотрим также замену getter get методом async.
Я не могу использовать Task.Wait()
или .Result
, потому что:
- Он тратит
ThreadPool
потоки в серверном приложении - Это приводит к взаимоблокировкам: если все
ThreadPool
потокиWait
ing, для выполнения каких-либо задач нет потоков.
Итак, вопрос в том, должен ли я сначала исправить все мои методы async
, даже если я не планирую вызывать что-либо асинхронное внутри? Разве это не повредит работе? Или как проектировать вещи, чтобы избежать таких сложных рефакторингов?