Для начала вы, вероятно, не работаете в .NET 4.0, потому что среды выполнения .NET 4.x являются двоичными заменами.Установка приложения .NET 4.5+ или исправления Windows Update означает, что все приложения теперь работают на .NET 4.5 и более поздних версиях.Ваша машина разработки работает по крайней мере на .NET 4.5+, что означает, что вы уже разрабатываете * отличную среду выполнения, чем та, на которую вы собираетесь ориентироваться.
Единственное исключение, если вы нацелены на неподдерживаемую ОСверсии, такие как Windows XP и Windows Server 2003, которые никогда не получали поддержку .NET 4.5.
В любом случае, использование Microsoft.Bcl.Async является жизнеспособным вариантом,поскольку вы уже приняли на себя гораздо большие риски, например, работаете на 4.5 и нацелены на 4.0 или работаете на неподдерживаемой ОС, у которой даже нет поддержки TLS1.2, минимальное требование для большинства сервисов в настоящее время, включая Google, AWS, Azure,банки, платежные шлюзы, авиакомпании и т. д.
Другой вариант заключается в использовании ContinueWith с параметром TaskScheduler
, который указывает, где запустить продолжение. TaskScheduler.FromCurrentSynchronizationContext () указывает, что продолжение будет выполняться в исходном контексте синхронизации.В приложении Winforms или WPF это поток пользовательского интерфейса.
Тогда мы писали такой код:
Task.Factory.StartNew(() => LongerOperation())
.ContinueWith(t =>
{
textBox.Text=String.Format("The result is {0}",t.Result);
},TaskScheduler.FromCurrentSynchronizationContext());
Обработка исключений и объединение в цепочку нескольких асинхронных операций требует дополнительной работы.t.Result
выдаст исключение, если задача не выполнена, поэтому вам нужно проверить Task.IsFapted или Task.IsCancelled , прежде чем пытаться использовать его значение.
Невозможно замкнуть цепь продолжений с помощью простого return
, как вы можете в .NET 4.5 и async / await.Вы можете проверить флаг IsFaulted
и избежать обновления пользовательского интерфейса, но вы не можете предотвратить выполнение продолжения next вниз по цепочке.
Task.Factory.StartNew(() => LongerOperation())
.ContinueWith(t=>
{
if (!t.IsFaulted)
{
return anotherLongOperation(t.Result);
}
else
{
//?? What do we do here?
//Pass the buck further down.
return Task.FromException(t.Exception);
}
})
.ContinueWith(t =>
{
//We probably need `Unwrap()` here. Can't remember
var result=t.Unwrap().Result;
textBox.Text=String.Format("The result is {0}",result);
},TaskScheduler.FromCurrentSynchronizationContext());
Чтобы остановить выполнение в случаев случае неудачи вам придется использовать параметр TaskContinuationOptions и передать, например, NotOnFaulted
.
Task.Factory.StartNew(() => LongerOperation())
.ContinueWith(t =>
{
textBox.Text=String.Format("The result is {0}",t.Result);
},
CancellationToken.None,
TaskContinuationOptions.NotOnFaulted,
TaskScheduler.FromCurrentSynchronizationContext());
Что делать, если вы хотите прекратить выполнение из-за какого-то бизнес-правила?Вам нужно будет вернуть что-то , которое все последующие шаги должны будут переслать до конца цепочки.
В конце, использование Microsoft.Bcl.Async
может привести к гораздо более простому коду
Task.Factory.StartNew(() => LongerOperation())
.ContinueWith(t=>
{
if (!t.IsFaulted)
{
var num=anotherLongOperation(t.Result);
if (num<0)
{
//Now what?
//Let's return a "magic" value
return Task.FromResult(null);
}
}
else
{
//?? What do we do here?
//Pass the buck further down.
return Task.FromException(t.Exception);
}
})
.ContinueWith(t =>
{
//This may need t.Result.Result
if (!t.IsFaulted && t.Result!=null)
{
textBox.Text=String.Format("The result is {0}",t.Result);
}
},TaskScheduler.FromCurrentSynchronizationContext());
Я не уверен, нужны ли продолжения внизу Unwrap()
или нет.Они, вероятно, делают, поскольку второй шаг возвращает Task<T>
.Забыв об этом, вы можете столкнуться с трудностями в отладке.
Использование Microsoft.Bcl.Async
приводит к более чистому и простому коду, который намного проще понять:
public async Task DoRun()
{
try
{
var x=await longOperation();
var num=await anotherLongOperation(x);
if(num<0)
{
return;
}
textBox.Text=String.Format("The result is {0}",num);
}
catch(Exception exc)
{
//Do something about it
}
}
Обновление
Как отметил Стивен Клири, BLC Async работал только с Visual Studio 2012. Он также больше не поддерживается и, вероятно, доступен только для загрузки для подписчиков MSDN.
Еще в 2010 году группа разработчиков Parallel выпустила несколько расширений и примеров для упрощения параллельной и асинхронной обработки, Дополнительные возможности параллельных расширений .Эта библиотека включала в себя такие расширения, как Then
, которые значительно упростили цепочку и обработку ошибок.
Большинство этих функций включены в саму .NET начиная с 4.5, поэтому образцы и библиотека не обновлялись с 2011 года. Любой NuGetпакеты или репозитории Github, которые претендуют на роль Parallel Extras, просто клонируют и перепаковывают эту загрузку.
Эта библиотека использовала для документирования серии статей Стивена Туба но Microsoft недавно изменила свой механизм ведения блогов, и URL-адреса старых перенесенных сообщений в блоге больше не работают.
Поскольку ни .NET 4.0, ни Parallel Extras не поддерживаются, ссылки не были исправлены.Эти статьи по-прежнему доступны под другим URL-адресом
«Больше не поддерживается» означает, что документы, библиотеки и знания также могут быть потеряны.Некоторые из тех, кто работал с заданиями 7 лет назад, могут помнить библиотеки и проекты, которые использовались тогда, но 7 лет - это слишком долго.