2013-04-16 24 views
7

Próbuję utworzyć interfejs serializacji (podobny do protokołu Cocoa o numerze NSCoding), aby uzyskać szybką binarną reprezentację klasy, która będzie wysyłana przez sieć lub sklep w bazie danych. Jednak niektóre przypadki (szczególnie związane z kodowaniem obrazu) mają wiele metod asynchronicznych, które wymagają zastosowania. Jeśli jednak bajty nie zostaną zapisane w kolejności, to oczywiście cała reprezentacja jest uszkodzona. Muszę się upewnić, że bieżący obiekt jest gotowy do serializacji, zanim przejdę do następnego obiektu. Oto główna pętla tego, co robię.Jak mogę obsłużyć metodę interfejsu, która może być lub może nie być asynchroniczna?

public async static Task<byte[]> Serialize(this IList<ISerializable> list) { 
     using (Archiver archiver = new Archiver()) { 
      archiver.Write(list.Count); 
      foreach (ISerializable value in list) { 
       await archiver.Write(value); 
      } 
      return archiver.Result; 
     } 
    } 

Archiver prostu wykorzystuje MemoryStream i BitmapWriter pod maską napisać albo wartości, które BinaryWriter może przyjąć bezpośrednio lub ISerializable obiekty, a następnie wypluwa wynik w postaci tablicy bajtów. ISerializable to tylko interfejs z dwiema metodami (Serialize i Deserialize). Oba zwracają numer Task, dzięki czemu mogą być edytowane pod numerem await. Problem polega na tym, że mam metodę serializacji, która nie zawiera żadnych komponentów asynchronicznych. Mogę wykonać jedną z dwóch rzeczy:

A) Mogę jednak przylepić się do async do metod serializacji tej klasy i na wszelki wypadek z ostrzeżeniem kompilatora, że ​​będzie wykonywał się synchronicznie (nie lubię ostrzeżeń kompilatora).

B) Ręcznie zwróć puste zadanie na końcu metody (return Task.Run(() => {});). Jednak wygląda i pachnie naprawdę dziwnie.

Zarówno A, jak i B wydają się wykonywać bez problemu, ale czy są jakieś problemy z tym podejściem, które mogłem przegapić? Nie wiem o serializatorze binarnym w środowisku wykonawczym systemu Windows (dodałem tag tylko po to, aby rozwiać wszelkie wątpliwości). Być może jest opcja C, którą mogę rozważyć? Właściwie nie chciałem, aby metody serializacji asynchronizowały się, ale z jakiegoś powodu task.Wait() nie czekał, a ja otrzymywałem zerowy wyjątek odniesienia, próbując użyć obiektu utworzonego z CreateAsync, zanim był gotowy.

EDIT Pomyślałem o opcji C. Mogłem po prostu zawinąć całą metodę w rozmowie await Task.Run(...). Czy to byłoby normalne?

+0

Możesz czekać na Task.Delay (0), natychmiast powróci. –

+0

@HansPassant Raczej podoba mi się to rozwiązanie ^^ – borrrden

+0

Czy Twój obraz przetwarza bibliotekę innej firmy? Pytam, ponieważ wydaje mi się, że kodowanie obrazu (i ogólnie serializacja) nie są naturalnie operacjami "asynchronicznymi". Powiedział, że wolę rozwiązanie @ svick, które jest jak opcja B z mniejszym obciążeniem. –

Odpowiedz

4

Myślę, że najlepszym rozwiązaniem tutaj, zakładając, że chcesz wykonać tę metodę synchronicznie, jest napisanie jej normalnie, z tym że zwróci ona zakończoną Task na końcu metody.

Aby uzyskać wypełniony Task o określonej wartości, można użyć Task.FromResult().

Jeśli chcesz Task bez wartości (czyli właściwie tylko Task nie Task<TResult>), można użyć na przykład Task.FromResult(true) (co jest Task<bool>) i niejawnie oddanych do Task.

+0

Jak to porównać, w twojej głowie, do sugestii w komentarzach 'Task.Delay (0)'? – borrrden

+0

@borrrden Praktycznie nie sądzę, że jest jakaś różnica. Logicznie myślę, że 'FromResult()' ma lepszy sens, ponieważ chcesz wykonać "zadanie", a nie opóźnienie. Ponadto wersją synchroniczną tego kodu jest 'Thread.Sleep (0)', który ma specjalne znaczenie. To może być mylące. – svick

Powiązane problemy