Metody asynchroniczne i zdarzenia - jak powinno się to robić?

0

Mam sobie klasę/bibliotekę, w której niestety muszę zrobić trochę metod asynchronicznych, które będą sobie wywoływały zdarzenia.

Obecnie metody synchroniczne są zarówno void, jak Login(), Logout() czy Insert(), ale będą też zwracające obiekty jak QueryResult GetOperations() czy List<Account> GetAccounts().

Login() obecnie albo się powiedzie, albo rzuci wyjątek - czy to jest dobra praktyka, czy raczej nie powinno przypadkiem zwracać boola? Bo obecnie mam wrażenie, że ta druga opcja jest bardziej naturalna. A jak w przypadku Insert(), który nic nie zwraca - błąd dodawania jest wyjątkiem, czy tylko false w zwracanej wartości?

Czy w wersji asynchronicznej powinienem mieć dla każdej metody coś w tym stylu:

public class OperationCompletedEventArgs : AsyncCompletedEventArgs
    {
        public OperationCompletedEventArgs(Exception error, bool cancelled, object userState)
            : base(error, cancelled, userState)
        {
        }
    }

public delegate void LoginCompletedEventHandler(
        object sender,
        OperationCompletedEventArgs e
    );

public void LoginAsync(string username, string password) { ... LoginCompleted.Invoke(this, new OperationCompletedEventArgs(...)); }

public event LoginCompletedEventHandler LoginCompleted;

Jest to dość rozbudowane i trochę się tego kodu robi - może OperationCompletedEventArgs jest identyczne dla Login i Logout, ale dla np. GetOperations to już mamy kolejne EventArgs i tak dalej.

To się powinno tak robić, czy można prościej/lepiej? Nie chcę używać async/await. Choć chciałbym aby użytkownik mojej biblioteki mógł z tego skorzystać, tak nawiasem.

Ostatnie pytanie - czy zwracanie List<Account> jest dobrą praktyką, czy powinienem raczej to sobie opakować w moją klasę?

0

O tradycyjnym modelu metod asynchronicznych masz tutaj: http://msdn.microsoft.com/en-us/library/hkasytyf
Metoda synchroniczna rzuca wyjątki, a asynchroniczna przechowuje je w obiekcie klasy MetodaEventArgs w polu error właśnie, czyli dokładnie tak jak to zrobiłeś.

EventArgs poleciłbym robić oddzielne dla każdej asynchronicznej metody, której typ wyniku jest inny. Z dodatkowej delegaty możesz zrezygnować i użyć generycznej EventHandler<T>.

W przypadku async/await sprawa jest jeszcze prostsza, bo tam możesz normalnie rzucić wyjątek i go złapać i jeżeli on wystąpi to runtime tam po prostu "wróci". W gruncie rzeczy będzie to prawie identyczne jak w przypadku metod synchronicznych.

Zwróciłbym raczej IEnumerable<Account>, jeżeli potrzebny jest tylko dostęp do tych obiektów - najczęściej właśnie tak jest.

0

async/await jest bardzo wygodne. do Visuala 2012 RC można doinstalować Async Targeting Pack, dzięki czemu async działa też we Frameworku 4.0, a wynikowy program ruszy pod XP.

1 użytkowników online, w tym zalogowanych: 0, gości: 1