Безопасно ли оставлять задачу без ссылки, если я точно знаю, что она не выдает исключение? Будет ли GC ждать, пока задача не будет завершена, прежде чем заберет ее?
Вот пример моего метода, который преобразует массив задач в одну задачу, которая завершается (отменяется или не выполняется), когда все задачи завершаются. Мое приложение завершается с ошибкой без наблюдения задачи (зарегистрировав Task.Id в любом месте, где я использую задачи, я обнаружил, что задача, которая осталась ненаблюдаемой, это та, которая поставляется этому методу или, по крайней мере, имеет тот же идентификатор). Я понятия не имею, почему это происходит, за исключением того, что сборщик мусора собирает задачу, возвращенную из Task.Factory.ContinueWhenAll, не ожидая, когда она будет завершена, как таковая, она также может собирать все мои задачи из массива, оставленного без ссылки, и если есть хотя бы одна неудачная задача это приведет к задаче ненаблюдаемого исключения. Звучит безумно, но я не вижу другого объяснения тому, что происходит. Так возможно ли это?
public static Task ToWhenAllTask(this Task[] tasks, bool cancelIfAnyCanceled = true)
{
if (tasks != null && tasks.Length == 0)
throw new ArgumentException();
var tcs = new TaskCompletionSource<object>();
Task.Factory.ContinueWhenAll(tasks, ts => {
try
{
List<Exception> errors = null;
bool canceled = false;
foreach (Task task in ts)
{
AggregateException ex = task.Exception;
if (ex != null)
{
if (errors == null)
errors = new List<Exception>();
errors.Add(ex.Flatten());
}
if (task.IsCanceled)
canceled = true;
}
if (errors != null)
tcs.TrySetException(errors);
else if (cancelIfAnyCanceled && canceled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(null);
}
catch(Exception ex)
{
// there is nothing to fail in this method but just in case
tcs.TrySetException(ex);
}
}, TaskContinuationOptions.ExecuteSynchronously);
return tcs.Task;
}
PS. Честно говоря, я думал, что до тех пор, пока задача не будет завершена, TaskScheduller будет содержать ссылку на нее (и в моем случае задача продолжения также содержит ссылку на массив задач). Поэтому GC не может собрать задачу продолжения и все задачи из массива, пока все они не завершатся.