Przedmowa : Szukam wyjaśnienia, a nie tylko rozwiązania. Znam już rozwiązanie.
Mimo, że spędziłem kilka dni na studiowaniu artykułów MSDN na temat Asynchronicznego Wzorca Asynchronicznego (TAP), asynchronizacji i czekania, nadal jestem nieco zdezorientowany niektórymi szczegółami.
Piszę program rejestrujący dla aplikacji ze Sklepu Windows i chcę obsługiwać zarówno rejestrowanie asynchroniczne, jak i synchroniczne. Metody asynchroniczne są zgodne z TAP, metody synchroniczne powinny to wszystko ukrywać i wyglądać i działać jak zwykłe metody.
Jest to podstawowa metoda rejestrowania asynchronicznego:
private async Task WriteToLogAsync(string text)
{
StorageFolder folder = ApplicationData.Current.LocalFolder;
StorageFile file = await folder.CreateFileAsync("log.log",
CreationCollisionOption.OpenIfExists);
await FileIO.AppendTextAsync(file, text,
Windows.Storage.Streams.UnicodeEncoding.Utf8);
}
Teraz odpowiednia metoda synchroniczna ...
Wersja 1 :
private void WriteToLog(string text)
{
Task task = WriteToLogAsync(text);
task.Wait();
}
Wygląda to poprawnie, ale nie działa. Cały program zawiesza się na zawsze.
Wersja 2 :
Hmm .. Może zadanie nie zostało rozpoczęte?
private void WriteToLog(string text)
{
Task task = WriteToLogAsync(text);
task.Start();
task.Wait();
}
To rzuca InvalidOperationException: Start may not be called on a promise-style task.
Wersja 3:
Hmm .. Task.RunSynchronously
brzmi obiecująco.
private void WriteToLog(string text)
{
Task task = WriteToLogAsync(text);
task.RunSynchronously();
}
To rzuca InvalidOperationException: RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method.
Wersja 4 (rozwiązanie):
private void WriteToLog(string text)
{
var task = Task.Run(async () => { await WriteToLogAsync(text); });
task.Wait();
}
To działa. Zatem 2 i 3 to niewłaściwe narzędzia. Ale 1? Co jest nie tak z 1 i jaka jest różnica do 4? Co powoduje, że 1 powoduje zawieszenie się? Czy jest jakiś problem z obiektem zadania? Czy istnieje nieoczywisty impas?