2010-09-16 15 views
30

Więc mam jakiś kod, który przechodzi wokół tego anonimowego obiektu pomiędzy metodami:C# 4: Dynamiczna i Nullable <>

var promo = new 
{ 
    Text = promo.Value, 
    StartDate = (startDate == null) ? 
     new Nullable<DateTime>() : 
     new Nullable<DateTime>(DateTime.Parse(startDate.Value)), 
    EndDate = (endDate == null) ? 
     new Nullable<DateTime>() : 
     new Nullable<DateTime>(DateTime.Parse(endDate.Value)) 
}; 

Metody, które otrzymają ten anonimowy typ obiektu zadeklarować jej typ jako dynamic:

private static bool IsPromoActive(dynamic promo) 
{ 
    return /* check StartDate, EndDate */ 
} 

W czasie działania, jednakże, jeśli StartDate lub EndDate są ustawione new Nullable<DateTime>(DateTime.Parse(...)), sposób, który odbiera ten dynamic obiektu (o nazwie promo) wykonuje sposób:

if (promo.StartDate.HasValue && promo.StartDate > DateTime.Today || 
    promo.EndDate.HasValue && promo.EndDate < DateTime.Today) 
{ 
    return; 
} 

zgłasza wyjątek:

Server Error in '/' Application. 
'System.DateTime' does not contain a definition for 'HasValue' 

Co tu się dzieje? Czego nie rozumiem w przypadku typów Nullable i słowa kluczowego dynamic?

Ten kod pracował dobrze, zanim zmieniłem usunąłem struct że wcześniej zapisany Text, StartDate i EndDate i zastąpił go typu anonimowego i przekazał go wokół jako dynamic.

+0

Masz 'promo.StartDate.HasValue', ale w tym samym czasie używasz' promo.StartDate', jakby była tą wartością. Ta niespójność wydaje się być błędem: użyj 'promo.StartDate.HasValue' i' promo.StartDate.Value' lub promo.StartDate == null' i 'promo.StartDate'. (Nie wiem, którego użyć, nie mam dostępnego .NET 4.0 do przetestowania.) Lub ... może być niejawny casting, ale nie wiem, czy to jest obsługiwane "dynamicznie" bardzo dobrze . – strager

+3

Nie używaj tej brzydkiej 'Nullable ' składni; zamiast tego użyj 'T?' :). – Domenic

+1

Interesujące odkrycie, bez typów dynamicznych, wymagałoby użycia HasValue i Value. Ale ponieważ boks w środowisku wykonawczym usuwa informacje nullable i pozostawia tylko wartość pudełkową lub wartość null, nie można używać tych właściwości. Więc nie używaj w ogóle HasValue, porównaj obiekt z wartością null. – IllidanS4

Odpowiedz

60

Świetne pytanie. Dwa fakty, których prawdopodobnie nie znasz:

  1. Dynamiczny za kulisami jest po prostu przedmiotem. Oznacza to, że zmienna "dynamiczna" jest zmienną "obiektową" z podpowiedzią dla kompilatora, który mówi "generuj dynamiczne operacje na tej zmiennej, gdy jest używana."

  2. Nie ma czegoś takiego, jak pudełko puste. Kiedy zapakujesz int? do obiektu otrzymasz odwołanie do obiektu o wartości NU lub pole do int. Nullable wrapper wokół int jest odrzucany.

Teraz powinno być jasne, co się tutaj dzieje. Jeśli promo jest dynamiczne, wówczas promo.StartDate jest dynamiczne. Co oznacza, że ​​w czasie wykonywania jest to obiekt. Co oznacza, że ​​jeśli ma wartość, jest zapakowany. Co oznacza, że ​​jeśli był on zerowalny, teraz jest to albo zerowa referencja, albo pudełkowa wartość nie podlegająca zerowaniu. Tak czy inaczej, rzecz ta nie ma właściwości HasValue. Jeśli chcesz się dowiedzieć, czy był to typ wartości z pustym typem wartości null, sprawdź, czy promo.StartDate ma wartość null, czy nie.

+1

Bardzo ładna odpowiedź. Z pewnością mnie oświeciło. –

+0

Mówisz, że środowisko wykonawcze traktuje 'Nullable ' specjalne w przypadku 'dynamic'? – strager

+8

@strager: Nie, to wcale nie jest to, co mówię. Środowisko wykonawcze wie * nic * o "dynamice". "dynamic" istnieje tylko w czasie kompilacji.* Środowisko wykonawcze traktuje Nullable jako specjalne podczas wykonywania instrukcji boksu. * –

Powiązane problemy