Metoda generyczna - problem z nullable DateTime

0

Cześć,

napisałem sobie metodę generyczną, która z założenia miała mi zwracać dane z SecureStorage (Android - Xamarin).

private T Get<T>(string paramName)
        {
            try
            {
                return (T)Convert.ChangeType(SecureStorage.GetAsync(paramName).Result, typeof(T));
            }
            catch (Exception)
            {
                return default;
            }
        }

Problem pojawia się przy DateTime?, np.:

Get<DateTime?>("klucz");

zwraca mi nulla mimo, że wartość jest ustawiona.

Metoda dla DataTime zwraca poprawną wartość, tylko, że je nie chcę dostawać 0001-01-01 w przypadku błędu, a nulla.

Co powinien poprawić?

1
kobi55 napisał(a):
SecureStorage.GetAsync(paramName).Result

Przede wszystkim przerobić metodę Get na asynchroniczną i pozbyć się tego .Result.

Co powinien poprawić?

Sprawdzić za pomocą refleksji, czy typ T jest Nullable<TInner>.

bool IsNullable(Type t, out Type ofType)
{
    if (!t.IsGenericType || t.GetGenericTypeDefinition() != typeof(Nullable<>))
    {
        ofType = default;
        return false;
    }

    ofType = t.GetGenericArguments()[0];
    return true;
}

Jeśli sprawdzisz to, czy podany T jest Nullable<TInner>, to zrób takiego ifa w metodzie Get, który to obsłuży.

0

@maszrum: Dziękuję za pomoc :)

Wyszło mi coś takiego:

private async Task<T> Get<T>(string paramName)
        {
            try
            {
                var value = await SecureStorage.GetAsync(paramName);
                return (T)Convert.ChangeType(value, IsNullable(typeof(T), out Type oftype) ? oftype : typeof(T));
            }
            catch (Exception)
            {
                return default;
            }
        }

i z tego co widzę wszystko działa poprawnie :)

0
maszrum napisał(a):
kobi55 napisał(a):
SecureStorage.GetAsync(paramName).Result

Przede wszystkim przerobić metodę Get na asynchroniczną i pozbyć się tego .Result.

ogladalem kiedys jakiegos goscia z Microsoftu, ktory mowil, ze jezeli juz nie da się zrobić asynca od góry to dołu, to zamiast Task.Result, powinno się

Task.GetAwaiter().GetResult()

Co o tym myślicie?

0
heyyou napisał(a):

ogladalem kiedys jakiegos goscia z Microsoftu, ktory mowil, ze jezeli juz nie da się zrobić asynca od góry to dołu, to zamiast Task.Result, powinno się

Task.GetAwaiter().GetResult()

Co o tym myślicie?

Różnica jest tylko taka, że to rozwiązanie wyrzuci wyjątek nieopakowany w AggregateException (w razie wystąpienia jakiegoś wyjątku). Oba rozwiązania są niepoprawne, bo oba z pewnym jakimś prawdopodobieństwem spowodują dead-locka. Ale tak - to rozwiązanie jest lepsze jeśli mamy porównywać.

2
maszrum napisał(a):

Oba rozwiązania są niepoprawne, bo oba z pewnym prawdopodobieństwem spowodują dead-locka.

Hmm, np. w ASP.NET Core imho to nigdy nie spowoduje deadlocka, więc to nie jest tak, że raz zadziała, a raz nie.
Nie wiem jak wygląda SynchronizationContext w Xamarinie.

Tutaj pewnie @Afish mógłby powiedzieć coś ciekawszego ;)

3
heyyou napisał(a):

ogladalem kiedys jakiegos goscia z Microsoftu, ktory mowil, ze jezeli juz nie da się zrobić asynca od góry to dołu, to zamiast Task.Result, powinno się

Task.GetAwaiter().GetResult()

Co o tym myślicie?

I tak, i nie. GetAwaiter w ogóle nie powinno być używane w kodzie użytkownika, bo jest to wystawione na potrzeby kompilatora i bebechów pod spodem, ale faktem jest, że inaczej to obsługuje wyjątki (troszkę lepiej). Ja bym jednak poszedł w Result.

maszrum napisał(a):

Oba rozwiązania są niepoprawne, bo oba z pewnym jakimś prawdopodobieństwem spowodują dead-locka.

Znowu, tak i nie. Ryzyko zakleszczenia jest, oczywiście zależy od reszty kodu, ale większym problemem jest blokowanie wątku systemu operacyjnego. O ile zakleszczenia da się uniknąć (albo obejść), o tyle blokady wątku już nie, a dokładniej, to ominięcie blokady wymaga trochę czarowania generatorami lub fiberami i w 99% przypadków nie ma sensu tego robić.

some_ONE napisał(a):

Hmm, np. w ASP.NET Core imho to nigdy nie spowoduje deadlocka, więc to nie jest tak, że raz zadziała, a raz nie.
Nie wiem jak wygląda SynchronizationContext w Xamarinie.

Tak i nie. Blokujesz wątek, więc zawsze możesz mieć zakleszczenie, ale musiałbyś explicite próbować wrzucić jakiś kod do wykonania na zablokowanym wątku, bo kontekstu synchronizacji nie ma, a tego raczej nikt nie robi, więc z tej perspektywy nie będzie zakleszczenia. Xamarin, Blazor, WPF, WinForms, WinRT mają jednowątkowe konteksty, więc tam ryzyko zakleszczenia jest wyższe.

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