2012-11-26 17 views
47

Mam aplikację. Ta aplikacja używa interfejsu do dostępu do bazy danych. Ten interfejs może być implementowany przez wiele klas. Na przykład jeden używa EF 4.4, ale inne klasy mogą używać EF5, który jest bardziej wydajny. W przyszłości może będę używał EF6, ponieważ używa on metod asynchronicznych. W tym przykładzie wszystkie metody używają EF, ale być może inne opcje mogą być użyte w inny sposób.Interfejsy i metody asynchroniczne

Aplikacja jest zakodowana jeden raz, używając interfejsu i zgodnie z plikiem konfiguracyjnym, użyj jednej lub drugiej implementacji, więc muszę tylko zmodyfikować kod w jednym miejscu, konstruktorze, aby dodać nową opcję w tworzenie instancji klasy przypisanej do interfejsu.

W tej chwili wszystkie metody klas nie są async, ale w przyszłości, jeśli używam EF6 Chciałbym użyć metod asynchronicznych, więc nie wiem, czy jest możliwe, że klasa, która używa EF6 i implementuje interfejs może korzystać z metod async.

Dla asynchronicznych metod EF6 użyłbym wzoru async/awiat, więc w metodzie mojej klasy muszę użyć atrybutu async. Dzięki temu mogę użyć słowa kluczowego await, gdy wywołuję metodę asynchroniczną EF6.

Ale ta klasa może implementować interfejs, który po raz pierwszy dotyczy metod synchronicznych?

Czy jest jakiś sposób, że w głównej aplikacji mogę używać wielu implementacji bez potrzeby modyfikacji kodu? Niektóre implementacje będą korzystać z metod asynchronicznych, podczas gdy inne będą synchroniczne.

+2

Należy pamiętać, że 'async' nie jest częścią podpisu; metoda asynchroniczna i nie asynchroniczna mogą implementować tę samą metodę interfejsu. – Servy

+1

To nie jest metoda, która jest godna uwagi, jest to typ (return). – rism

+1

Zbyt wiele wyjaśnień na proste pytanie. MOIM ZDANIEM. – Mahmoodvcs

Odpowiedz

55

async nie jest częścią podpisu, więc w rzeczywistości nie muszą być związane z czy metoda realizacji interfejs jest async czy nie, trzeba tylko być związane z typami właściwości poszczególnych typ zwrotu, nazwę metody i dostępność.

prawdziwy różnicą jest to, że metody async będą musiały zwrócić Task lub Task<T>, natomiast metody nie są asynchroniczne najprawdopodobniej obecnie powrocie void albo jakiś rodzaj, T bezpośrednio.

Jeśli chcesz "przyszłościowo potwierdzić" swoją aplikację, jedną z opcji jest upewnienie się, że wszystkie twoje interfejsy zwracają Task lub Task<T>, a dla implementacji EF4/EF5 wyniki są zawijane, nawet jeśli są wykonywane. synchronicznie.

Task.FromResult został dodany w .NET 4.5, ale jeśli nie masz to możesz napisać własną rękę dość łatwo:

public static Task<T> FromResult<T>(T result) 
{ 
    var tcs = new TaskCompletionSource<T>(); 
    tcs.SetResult(result); 
    return tcs.Task; 
} 

Można również napisać CompletedTask metodę, która zwraca po prostu zadania, które już ma ukończone: (to buforuje pojedynczego zadania ze względu na efektywność.)

private static Task _completedTask; 
public static Task CompletedTask() 
{ 
    return _completedTask ?? initCompletedTask(); 
} 

private static Task initCompletedTask() 
{ 
    var tcs = new TaskCompletionSource<object>(); 
    tcs.SetResult(null); 
    _completedTask = tcs.Task; 
    return _completedTask; 
} 

te dwie metody uprości proces mający wszystkich metod powracających jakiś rodzaj Task, choć robi to uczyni Twój kod bi t messier, dopóki nie będziesz w stanie użyć C# 5.0, aby móc uzyskać wynik w postaci await.

+0

, więc jedynym rozwiązaniem jest wymuszenie na wszystkich klasach, aby zwrócić zadanie? –

+1

Cóż, to nie jest jedyne rozwiązanie. To najlepszy, jaki wymyśliłem. Jeśli masz C# 5.0, ale po prostu nie EF 6.0, możesz nadal "czekać" na wyniki wywołania metody (nawet jeśli są już zakończone), co sprawi, że nie będzie to zbyt straszne. – Servy

+6

W takiej sytuacji (gdy twoje operacje są naturalnie asynchroniczne), możesz albo spowodować, że wszystkie metody zwrócą 'Zadanie', albo utworzą jednocześnie metody synchroniczne i asynchroniczne. –