Doszedłem się z następującymi definicjami. Parametry defaultValue
są głównie w stanie przeciążać metodę TryGet
, ponieważ ograniczenia ogólne nie są częścią sygnatury metody, co sprawia, że metoda jest unikalna przy podejmowaniu decyzji, która metoda wywołać (na przykład, typ powrotu nie jest również częścią podpis).
public async Task<T> TryGet<T>(Func<Task<T>> func, T defaultValue = null) where T : class
{
try
{
return await func();
}
catch (ArgumentException)
{
return defaultValue;
}
catch (FormatException)
{
return defaultValue;
}
catch (OverflowException)
{
return defaultValue;
}
}
public async Task<Nullable<T>> TryGet<T>(Func<Task<T>> func, Nullable<T> defaultValue = null) where T : struct
{
try
{
return await func();
}
catch (ArgumentException)
{
return defaultValue;
}
catch (FormatException)
{
return defaultValue;
}
catch (OverflowException)
{
return defaultValue;
}
}
Należy przejrzeć obsługę wyjątków, przykład ten obsługuje wspólne wyjątki analizowania. Może być bardziej sensowne reagowanie na inne wyjątki, takie jak InvalidOperationException
i NotSupportedException
, prawdopodobnie najczęściej używane typy wyjątków w samej strukturze (niekoniecznie najczęściej wyrzucane).
Innym podejściem jest ponowne rzucenie krytycznych wyjątków, takich jak ThreadAbortException
i proste klauzula catch-all, która zwraca wartość domyślną. Jednak spowoduje to ukrycie każdego wyjątku, który nie zostanie uznany za krytyczny, niezależnie od tego, jak poważny jest.
Jako taki, a ponieważ wyjątki od rzucania są kosztowną operacją, jest to Parse
, które jest zwykle definiowane jako TryParse
. Twój TryGet
powinien więc zawierać umowę, np. do czynienia z OperationCanceledException
, która obejmuje TaskCanceledException
i nic więcej.
Na koniec należy podać nazwę TryGetAsync
, zgodnie z konwencją przyrostków Async. [1][2]
Dopóki ta składnia https://github.com/dotnet/roslyn/issues/347 nie zostanie zaimplementowana, wydaje się, że jesteś skazany na to, by po prostu zwrócić swój własny typ.Przynajmniej używaj Tuple (lub lepszego niestandardowego typu z rozsądnymi nazwami właściwości, takimi jak Sukces i Wynik), a nie KeyValuePair. –
Evk
Thx za link, fajna propozycja! Jaka jest korzyść z Tuple <> ponad KVP <>? Zawsze muszę zwrócić dokładnie dwie rzeczy, wynik prawdziwy/fałszywy i rzeczywistą ładowność. Nienawidzę nazw właściwości 'Tuple <>' ('.Item1',' .Item2' ... całkowicie nieprzezroczystych do tego, co trzyma krotka.). 'KVP' nie jest dużo lepszy (w moim scenariuszu), ale przynajmniej' .Value' sprawia, że * jakiś * sens. –
Różnica jest tylko semantyką. KeyValuePair to, cóż, klucz + wartość. W twoim przypadku nic naprawdę nie jest kluczowe. Tuple to tylko dwie (lub więcej) dowolne wartości - Twoja sprawa. Jeśli nie lubisz nazw, utwórz własną klasę TryAsyncResult z właściwościami bool i T z odpowiednimi nazwami. Potrzebujesz tylko jednej takiej klasy dla wszystkich twoich operacji Try (z powodu generycznych). –
Evk