Nullable <int> vs. int? - Czy jest jakaś różnica?


94

Najwyraźniej Nullable<int>i int?mają równoważną wartość. Czy są jakieś powody, aby wybrać jeden z nich?

Nullable<int> a = null;
int? b = null;
a == b; // this is true

Odpowiedzi:


135

Bez różnicy.

int?jest tylko skrótem Nullable<int>, co samo w sobie jest skrótem Nullable<Int32>.

Skompilowany kod będzie dokładnie taki sam, niezależnie od tego, który wybierzesz.


1
Niestety zdarzają się przypadki, w których nie jest to do końca prawdą. Zobacz tę odpowiedź .
qqbenq

22

?Forma jest po prostu skrótem dla pełnego typu. Osobiste preferencje to jedyny powód, aby wybrać jedną z nich.

Pełne szczegóły tutaj .

Składnia T?jest skrócona Nullable<T>, gdzie Tjest typem wartości. Te dwie formy są wymienne.


18

A ja całkowicie zgadzam się, że w większości przypadków są one takie same, Niedawno natknąłem się na sytuacji, gdy nie jest różnica między tymi dwoma. Aby poznać krwawe szczegóły, zobacz to pytanie , ale aby dać ci szybki przykład tutaj:

void Test<T>(T a, bool b)
{
    var test = a is int? & b;              // does not compile
    var test2 = a is Nullable<int> & b;    // does compile
}

Pierwsza linia zawiera następujące komunikaty o błędach:

error CS1003: Syntax error, ':' expected 
error CS1525: Invalid expression term ';'

Jeśli ciekawi cię dokładny powód tego, naprawdę polecam sprawdzenie już połączonego pytania , ale podstawowym problemem jest to, że w fazie parsowania po operatorze is(lub as), gdy napotykamy ?token, sprawdzamy, czy następny token może być interpretowany jako operator jednoargumentowy ( &może być jednym), a jeśli tak: parser nie dba o możliwość, że ?token jest modyfikatorem typu, po prostu używa typu przed nim, a resztę przeanalizuje tak, jakby ?token był operatorem trójargumentowym (dlatego analiza nie powiedzie się).

Tak więc, chociaż ogólnie int?i Nullable<int>są wymienne, są pewne narożne przypadki, w których dają one zupełnie inne wyniki, z powodu tego, jak parser widzi twój kod.


2
Pierwszy przypadek test,, jest oznaczony nawiasem, więc var test = (a is int?) & b;. Może być również mocowane var test = a is int? && b;, i biorąc pod uwagę, że bjest to parametr wartość proste (bez skutków ubocznych na ocenę) wydaje dziwne wolą &ponad &&.
Jeppe Stig Nielsen

W tej szczególnej składni ?jest kluczowym znakiem.
Pete Garafano

Zobacz powiązane pytanie i odpowiedź, wszystkie twoje komentarze są tam skierowane :) Właśnie dodałem te informacje tutaj, ponieważ uznałem, że jest to istotne, ponieważ podkreśla różnicę między dwiema formami i udowadnia, że ​​nie jest to tylko cukier syntaktyczny
qqbenq

Jeppe ma rację. Nie kompiluje się, ponieważ interpretuje int?jako operację trójskładnikową ( var test = a is int? <return if true> : <return if false>), a nie int.
Levi Fuller

1
@LeviFuller (kontynuacja) Zapoznaj się z dokumentacją dotyczącą tych konkretnych boolprzeciążeń. Są to logiczne operatory boolowskie ( &for bool) i warunkowe operatory logiczne boolowskie ( &&for bool). Zwróć uwagę, że pierwsza z tych podsekcji jest wyraźnie nazwana logiczną . Pamiętaj, że w C # nie ma konwersji („rzutów”) między booltypami numerycznymi!
Jeppe Stig Nielsen

6

Najwyraźniej istnieje różnica między nimi w przypadku korzystania z generowania Entity Framework (EF) w pierwszej kolejności:

Gdy Twój podmiot zawiera deklarowaną właściwość, taką jak:

public class MyEntity
{
    public Nullable<int> MyNullableInt { get; set; } 
}

EF nie wygeneruje właściwości dopuszczającej wartość null i będziesz musiał wymusić na generatorze, aby był on dopuszczalny w następujący sposób:

public class YourContext : DbContext
{
    public DbSet<MyEntity> MyEntities{ get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<MyEntity>().Property(x => x.MyNullableInt).IsOptional();
    }
}

Z drugiej strony, jeśli zadeklarujesz swój podmiot w następujący sposób:

public class MyEntity
{
     public int? MyNullableInt { get; set; }
}

generator EF będzie generował właściwość dopuszczającą wartość null z polem dopuszczającym wartość null w odpowiedniej tabeli bazy danych.


2
To naprawdę niefortunne.
Siride

8
To sugeruje, że masz Nullablegdzieś inną definicję, ponieważ przy wbudowanej Nullable<T>EF nie jest w stanie zobaczyć różnicy między nimi. Nawet jeśli pracownicy EF chcieli traktować ich inaczej, nie mogli.

1
Czy ktoś potwierdził, że tak jest? (tylko trochę ostrożny z powodu negatywnych głosów)
RayLoveless

@RayL Nie, tak nie jest. Ta odpowiedź nie jest poprawna i jak wskazała hvd, niemożliwa.
But

1
Biorąc pod uwagę, że kod EF jest generowany przy użyciu szablonów kodu, w rzeczywistości może to być możliwe. Moja odpowiedź jest oparta na moim doświadczeniu i sugerowanej przeze mnie zmianie rozwiązała problem, który miałem. Wydaje się również, że niektórzy ludzie stwierdzili, że rzeczywiście tak jest na podstawie głosów pozytywnych.
Maciej

2

Nullable to typ ogólny, ale int? nie jest.

Istnieje kilka scenariuszy, w których Nullable powinno być używane w int?

na przykład: tutaj nie można zastąpić pustych z int?

jak zmienić poniższy kod bez używania wartości Nullable ?

class LazyValue<T> where T : struct
{
   private Nullable<T> val;
   private Func<T> getValue;

   // Constructor.
   public LazyValue(Func<T> func)
   {
      val = null;
      getValue = func;
   }

   public T Value
   {
      get
      {
         if (val == null)
            // Execute the delegate.
            val = getValue();
         return (T)val;
      }
   }
}

3
Co może mieć znaczenie, gdyby pytanie dotyczyło typów ogólnych, ale pytanie zawierało int, więc tak nie Nullable<T>jestNullable<int>
Andrew,
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.