Вы можете использовать следующий метод для выполнения последовательности задач и создания новой последовательности задач, которые представляют начальные задачи, но возвращаются в порядке их завершения:
public static IEnumerable<Task<T>> Order<T>(this IEnumerable<Task<T>> tasks)
{
var taskList = tasks.ToList();
var taskSources = new BlockingCollection<TaskCompletionSource<T>>();
var taskSourceList = new List<TaskCompletionSource<T>>(taskList.Count);
foreach (var task in taskList)
{
var newSource = new TaskCompletionSource<T>();
taskSources.Add(newSource);
taskSourceList.Add(newSource);
task.ContinueWith(t =>
{
var source = taskSources.Take();
if (t.IsCanceled)
source.TrySetCanceled();
else if (t.IsFaulted)
source.TrySetException(t.Exception.InnerExceptions);
else if (t.IsCompleted)
source.TrySetResult(t.Result);
}, CancellationToken.None, TaskContinuationOptions.PreferFairness, TaskScheduler.Default);
}
return taskSourceList.Select(tcs => tcs.Task);
}
Теперь, когда вы имеют возможность заказывать задачи на основе их завершения, вы можете написать код в основном так, как ваши требования диктуют:
foreach(var task in myTaskList.Order())
if(!await task)
cancellationTokenSource.Cancel();
Да, сохраните его к переменной и отсоедините его.
DelegateType evt = (o, e) => { firedCount++; Console.Write(firedCount); };
foo.AnEvent += evt;
foo.MethodThatFiresAnEvent();
foo.AnEvent -= evt;
И да, если Вы не делаете, Вы будете утечка память, поскольку Вы поднимете трубку новый объект делегата каждый раз. Вы также заметите это, потому что каждый раз Вы называете этот метод, он выведет к консоли растущее число строк (не только растущее число, но и для одного вызова к MethodThatFiresAnEvent он выведет любое количество объектов, однажды для каждого поднятого трубку анонимного метода).
Хорошо можно расширить то, что было сделано здесь для создания делегатов более в безопасности использовать (никакие утечки памяти)
Вы привычка просто пропускает память, Вы также назовете свою лямбду многократно. Каждый вызов 'PotentialMemoryLeaker' добавит другую копию лямбды к списку событий, и каждую копию назовут, когда 'AnEvent' будет запущен.
Ваш пример просто компилирует в названный компилятором частный внутренний класс (с полем firedCount и названным компилятором методом). Каждый вызов к PotentialMemoryLeaker создает новый экземпляр класса закрытия, на, который где нечто сохраняет ссылку посредством делегата в отдельном методе.
, Если Вы не ссылаетесь на целый объект, который владеет PotentialMemoryLeaker, затем это будет все собрано "мусор". Иначе можно или установить нечто , чтобы аннулировать или освободить список обработчика событий нечто путем записи этого:
foreach (var handler in AnEvent.GetInvocationList()) AnEvent -= handler;
, Конечно, Вам был бы нужен доступ к члены парламента, не занимающие официального поста MyObject класса.
Да таким же образом, что нормальные обработчики событий могут вызвать утечки. Поскольку лямбда на самом деле изменяется на:
someobject.SomeEvent += () => ...;
someobject.SomeEvent += delegate () {
...
};
// unhook
Action del = () => ...;
someobject.SomeEvent += del;
someobject.SomeEvent -= del;
Так в основном это - просто стенография для того, что мы использовали в 2,0 все эти годы.