Jak przekonwertować C # nullable int na int


483

Jak przekonwertować nullable intna int? Załóżmy, że mam 2 typy int, jak poniżej:

int? v1;  
int v2; 

Chcę przypisać v1wartość do v2. v2 = v1;spowoduje błąd. Jak przekonwertować v1na v2?


Jakie jest pożądane zachowanie, kiedy v1jest null?
Solomon Ucko

Odpowiedzi:


637

Wszystkie dotychczasowe odpowiedzi są poprawne; Chciałem tylko dodać jeszcze jeden, który jest nieco czystszy:

v2 = v1 ?? default(int);

Każde Nullable<T>jest domyślnie konwertowalne na jego T, ZAPEWNIONE, że całe oceniane wyrażenie nigdy nie może spowodować przypisania wartości NULL do ValueType. Tak więc operator zerowania koalescencyjnego ??jest po prostu cukrem składniowym dla operatora trójskładnikowego:

v2 = v1 == null ? default(int) : v1;

... który z kolei jest składnią cukru dla if / else:

if(v1==null)
   v2 = default(int);
else
   v2 = v1;

Ponadto, od .NET 4.0, Nullable<T>ma metodę „GetValueOrDefault ()”, która jest zerowo bezpiecznym narzędziem pobierającym, które zasadniczo wykonuje koalescencję zerową pokazaną powyżej, więc to też działa:

v2 = v1.GetValueOrDefault();

4
Czy default(int)naprawdę jest potrzebny? Co jest złego w prostym 0?
Cole Johnson

4
To zadziałałoby w tym przykładzie, ale w ogólnym przypadku zaleca się użycie w defaultrazie potrzeby. Zero nie zawsze jest poprawne jako wartość, a tym bardziej nie jest wartością domyślną, więc jeśli zamienisz intna ogólny, Tzauważysz, że mój kod działa, a zero nie. W niektórych przyszłych wersjach ramowych defaultmoże również stać się przeciążalny; jeśli i kiedy tak się stanie, kod korzystający z domyślnego kodu będzie mógł łatwo skorzystać, a jawne przypisania zerowe lub zerowe będą musiały zostać zmienione.
KeithS

5
Powinno to wzrosnąć do góry: .NET 4.0, Nullable <T> ma „GetValueOrDefault ()”
RandomHandle

Dziękujemy za powrót do edycji za pomocą GetValueOrDefault!
CindyH,

Podczas korzystania z wartości domyślnych warto zachować ostrożność podczas korzystania z funkcji DateTime. Może to wstawić domyślną datę zamiast pustej.
Ranch Camal


92

Do przypisania można użyć właściwości Value.

v2 = v1.Value;

8
Ponadto - jeśli nie masz pewności, czy wersja 1 zawiera wartość null - możesz użyć operatora zerowania i koalescencji, aby ustawić wartość rezerwową. Np. V2 = v1 ?? 0;
Arjen

12
I v1.HasValuenajpierw sprawdź .
Fuj

3
MSDN mówi, że spowoduje to wyjątek, jeśli tak v1jest null. Moim zdaniem nie jest to poprawna odpowiedź.
ventiseis

6
@ventiseis Myślę, że to pożądane zachowanie - jestem zaskoczony, że wiele innych odpowiedzi jest w porządku, cicho przekształcając wartość zerową na 0. Jeśli przypisujesz typ zerowalny do typu, który nie ma wartości zerowej, powinieneś być pewien, że wartość nie jest faktycznie zerowa. OP nie powiedział: „Chcę przypisać v1 do v2 lub 0, jeśli v1 ma wartość zerową”, ale wszyscy tak zakładają
Michael Mrozek


49

Jeśli wiesz, że v1ma wartość, możesz użyć Valuewłaściwości:

v2 = v1.Value;

Użycie GetValueOrDefaultmetody spowoduje przypisanie wartości, jeśli istnieje, w przeciwnym razie wartość domyślna dla typu lub wartość domyślna, którą określisz:

v2 = v1.GetValueOrDefault(); // assigns zero if v1 has no value

v2 = v1.GetValueOrDefault(-1); // assigns -1 if v1 has no value

Możesz użyć HasValuewłaściwości, aby sprawdzić, czy v1ma wartość:

if (v1.HasValue) {
  v2 = v1.Value;
}

Istnieje również obsługa języka dla tej GetValueOrDefault(T)metody:

v2 = v1 ?? -1;

Nie należy używać tej wartości bez uprzedniego sprawdzenia, czy istnieje wartość. Użyj ?? zamiast tego operator.
Peter

45

Nie możesz tego zrobić, jeśli wersja 1 ma wartość NULL, ale możesz to sprawdzić u operatora.

v2 = v1 ?? 0;

28

GetValueOrDefault()

pobiera wartość obiektu. Jeśli ma wartość null, zwraca wartość domyślną int, która wynosi 0.

Przykład:

v2= v1.GetValueOrDefault();


21

Jeśli wartość domyślna dla danego typu jest akceptowalnym wynikiem:

if (v1.HasValue)
    v2 = v1.GetValueOrDefault();

Jeśli chcesz inną wartość domyślną, gdy wynik jest niezdefiniowany:

v2 = v1.GetValueOrDefault(255);    // or any valid value for int in place of 255

Jeśli chcesz tylko zwrócić wartość (bez względu na to, czy metoda zawiodła, czy nie):

v2 = v1.GetValueOrDefault();


.NET 4.7.2 .: GetValueOrDefault()zwraca wartość pola bez sprawdzania.


15

Moim zdaniem najlepszym rozwiązaniem jest użycie GetValueOrDefault()metody.

v2 = v1.GetValueOrDefault();

ten był dla mnie najbardziej przydatny
Liakat

11

Zamiana int nullable na int może być wykonana w następujący sposób:

v2=(int)v1;

9
Jeśli wersja 1 ma wartość NULL, spowoduje to wyjątek InvalidOperationException.
MungeWrath

10

jest to możliwe dzięki v2 = Convert.ToInt32(v1);


Będzie to działać technicznie, ale inne techniki, takie jak HasValue / Value lub GetValueOrDefault, działają znacznie wydajniej.
Brandon Barkley


9

Prosta konwersja między v1i v2nie jest możliwa, ponieważ v1ma większą domenę wartości niż v2. To wszystko v1może utrzymać plus nullpaństwo. Aby przekonwertować, musisz wyraźnie określić, jaka wartość intzostanie użyta do zmapowania nullstanu. Najprostszym sposobem na to jest ??operator

v2 = v1 ?? 0;  // maps null of v1 to 0

Można to również zrobić w długiej formie

int v2;
if (v1.HasValue) {
  v2 = v1.Value;
} else {
  v2 = 0;
}

9

W zależności od kontekstu użytkowania możesz użyć funkcji dopasowania wzorców w C # 7:

int? v1 = 100;
if (v1 is int v2)
{
    Console.WriteLine($"I'm not nullable anymore: {v2}");
}

EDYTOWAĆ:

Ponieważ niektórzy ludzie oddają głos bez pozostawienia wyjaśnienia, chciałbym dodać kilka szczegółów wyjaśniających uzasadnienie włączenia tego jako realnego rozwiązania.

  • Dopasowywanie wzorców w C # 7 pozwala nam teraz sprawdzić typ wartości i rzucić ją niejawnie. W powyższym fragmencie warunek if przejdzie tylko wtedy, gdy przechowywana wartość v1jest zgodna z typem dla typu v2, czyli w tym przypadku int. Wynika z tego, że gdy wartość dla v1jest null, warunek if zakończy się niepowodzeniem, ponieważ nie można przypisać wartości null do zmiennej int. Mówiąc dokładniej, nullnie jest int.

  • Chciałbym podkreślić, że to rozwiązanie nie zawsze może być optymalnym wyborem. Jak sugeruję, uważam, że będzie to zależeć od dokładnego kontekstu użytkowania programisty. Jeśli masz już int?i chcesz warunkowo operować na jej wartości, jeśli-i-tylko-jeśli przypisana wartość nie jest równa null (jest to jedyny czas, kiedy można bezpiecznie przekonwertować dopuszczalną wartość int na zwykłą liczbę int bez utraty informacji), to dopasowanie wzorca jest prawdopodobnie jednym z najbardziej zwięzłych sposobów na zrobienie tego.


Konieczność wprowadzenia nowej nazwy zmiennej jest niefortunna, ale jest to najlepsze (najbezpieczniejsze) rozwiązanie, jeśli nie ma wartości domyślnej, ponieważ nie ma ryzyka przypadkowego refaktoryzacji HasValueczeków.
minexew

Po prostu nie widzę żadnej przewagi tej metody nad v1.HasValue jako czekiem, a następnie v1.Value, aby uzyskać dostęp do wartości bazowej. Nie głosowałbym za tym, ale myślę, że ten problem został już rozwiązany, a nowa technika nie dodaje mu większej przejrzystości. Testowałem go również jako 8-9% wolniejszy.
Brandon Barkley

Dziękujemy za przeprowadzenie testu porównawczego, to dobrze wiedzieć! Tak czy inaczej, różnica jest w najlepszym razie marginalna (chyba że zrobisz to w krytycznym dla siebie obszarze, jak sądzę). Patrzę na to, że jest to bardziej „zwięzłe” lub być może „idiomatyczne”, ponieważ opiera się na cukrach składniowych upieczonych w języku zamiast API. Jest to nieco subiektywne, ale może „łatwiejsze w utrzymaniu”. Chociaż tak naprawdę podoba mi się to podejście bardziej niż poleganie na wartości domyślnej, jak sugeruje wiele innych odpowiedzi.
Nicholas Miller

3

Przydzieli wartość v1do, v2jeśli nie jest zerowa, w przeciwnym razie przyjmie wartość domyślną jako zero.

v2=v1??0

Lub poniżej jest inny sposób, aby to napisać.

v2 = v1.HasValue?v1:0


-1
 int v2= Int32.Parse(v1.ToString());

5
Chociaż ten kod może odpowiedzieć na pytanie, zapewnienie dodatkowego kontekstu dotyczącego tego, dlaczego i / lub jak ten kod odpowiada na pytanie, poprawia jego długoterminową wartość.
Xiawi

1
Lepiej jest użyć metody „najlepszej praktyki” do rozpakowywania opcjonalnych opcji, zamiast używać podstępnych sztuczek. Zobacz dokument docs.microsoft.com/en-us/dotnet/csharp/language-reference/ ...
lorg

Odpowiadając na ośmioletnie pytanie z piętnastoma istniejącymi odpowiedziami, ważne jest, aby wyjaśnić, jaki nowy aspekt pytania dotyczy twoja odpowiedź, i zauważyć, czy upływ czasu zmienił odpowiedź. Tylko odpowiedzi na kod można prawie zawsze poprawić, dodając pewne wyjaśnienia.
Jason Aller
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.