Nullable <int> vs. int? - Gibt es einen Unterschied?

93

Anscheinend Nullable<int>und int?sind im Wert gleichwertig. Gibt es Gründe, sich für einen anderen zu entscheiden?

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

Antworten:

134

Kein Unterschied.

int?ist nur eine Abkürzung für Nullable<int>, für die selbst eine Abkürzung ist Nullable<Int32>.

Der kompilierte Code ist genau derselbe, den Sie verwenden möchten.

LukeH
quelle
1
Leider gibt es einige Eckfälle, in denen dies nicht unbedingt zutrifft. Siehe diese Antwort .
QQBENQ
22

Das ?Formular ist nur eine Abkürzung für den vollständigen Typ. Persönliche Vorlieben sind der einzige Grund, sich für eine andere zu entscheiden.

Alle Details hier .

Die Syntax T?ist eine Abkürzung für Nullable<T>, wobei Tes sich um einen Werttyp handelt. Die beiden Formen sind austauschbar.

Steve Townsend
quelle
18

Während ich völlig einig , dass in den meisten Fällen die gleichen sind, ich kam vor kurzem in einer Situation, wenn es ist ein Unterschied zwischen diesen beiden. Für die blutigen Details siehe diese Frage , aber um Ihnen hier ein kurzes Beispiel zu geben:

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
}

Die erste Zeile enthält die folgenden Fehlermeldungen:

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

Wenn Sie neugierig auf den genauen Grund dafür sind, empfehle ich Ihnen wirklich, die bereits verknüpfte Frage zu überprüfen. Das Grundproblem besteht jedoch darin, dass wir in der Analysephase nach einem is(oder einem as) Operator, wenn wir einem ?Token gegenüberstehen, prüfen, ob die nächste Frage vorliegt Token kann als unärer Operator interpretiert werden ( &könnte einer sein) und wenn ja: Der Parser kümmert sich nicht um die Möglichkeit, dass das ?Token ein Typmodifikator ist, er verwendet einfach den Typ davor und analysiert den Rest so, als ob der ?Token waren ein ternärer Operator (daher schlägt die Analyse fehl).

Während also im allgemeinen int?und Nullable<int>untereinander austauschbar sind, gibt es einige Sonderfälle , wenn sie völlig unterschiedlichen Ergebnissen führen, weil, wie der Parser Code sieht.

qqbenq
quelle
2
Der erste Fall testist also mit einer Klammer festgelegt var test = (a is int?) & b;. Kann auch mit fixiert werden var test = a is int? && b;, und da bein einfacher Wert Parameter (keine Nebenwirkungen auf Auswertung) scheint es seltsam zu bevorzugen &über &&.
Jeppe Stig Nielsen
In dieser speziellen Syntax ?ist ein Schlüsselzeichen.
Pete Garafano
Siehe die verknüpfte Frage und Antwort, Ihre Kommentare werden alle dort angesprochen :) Ich habe diese Informationen hier hinzugefügt, da ich sie für relevant hielt, da sie einen Unterschied zwischen den beiden Formen hervorheben und beweisen, dass es sich nicht nur um syntaktischen Zucker handelt
qqbenq
Jeppe ist richtig. Es wird nicht kompiliert, da es int?als ternäre Operation ( var test = a is int? <return if true> : <return if false>) interpretiert wird , nicht als nullable int.
Levi Fuller
1
@LeviFuller (Fortsetzung) Informationen zu diesen bestimmten boolÜberladungen finden Sie in der Dokumentation . Dies sind boolesche logische Operatoren (das &für bool) und boolesche bedingte logische Operatoren (das &&für bool). Beachten Sie, wie der erste dieser Unterabschnitte eindeutig als logisch bezeichnet wird . Denken Sie daran, dass es in C # keine Konvertierungen ("Casts") zwischen boolund numerischen Typen gibt!
Jeppe Stig Nielsen
6

Bei der Verwendung der Code-First-Entity-Framework-Generierung (EF) besteht anscheinend ein Unterschied zwischen beiden:

Wenn Ihre Entität eine Eigenschaft enthält, die wie folgt deklariert ist:

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

EF generiert keine nullbare Eigenschaft und Sie müssen den Generator zwingen, sie wie folgt nullbar zu machen:

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();
    }
}

Auf der anderen Seite, wenn Sie Ihre Entität wie folgt deklarieren:

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

Der EF-Generator generiert eine nullfähige Eigenschaft mit einem nullbaren Feld in der entsprechenden Datenbanktabelle.

Maciej
quelle
2
Das ist wirklich unglücklich.
Siride
8
Das deutet darauf hin, dass Sie Nullableirgendwo eine andere Definition haben, da Nullable<T>EF mit der integrierten Funktion den Unterschied zwischen beiden nicht erkennen kann. Selbst wenn die EF-Leute sie anders behandeln wollten, konnten sie es nicht.
1
Hat jemand bestätigt, dass dies der Fall ist? (nur ein wenig vorsichtig wegen der negativen Stimmen)
RayLoveless
@ RayL Nein, das ist nicht der Fall. Diese Antwort ist nicht korrekt und, wie hvd betonte, unmöglich.
Schuh
1
In Anbetracht der Tatsache, dass EF-Code mithilfe von Codevorlagen generiert wird, ist dies möglicherweise tatsächlich möglich. Meine Antwort basiert auf meiner Erfahrung und die von mir vorgeschlagene Änderung hat das Problem behoben, das ich hatte. Es scheint auch, dass einige Leute festgestellt haben, dass dies tatsächlich der Fall ist, basierend auf den Up-Votes.
Maciej
2

Nullable ist ein generischer Typ, aber int? ist nicht.

Es gibt einige Szenarien, in denen Nullable über int verwendet werden sollte.

für zB: hier kann man nicht ersetzen Nullable mit int?

Wie können Sie den folgenden Code ändern, ohne Nullable zu verwenden ?

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;
      }
   }
}
Rajes
quelle
2
Welche Rolle könnte , wenn die Frage nach generische Typen fragte, aber die Frage int festgelegt hat, so ist es nicht Nullable<T>es istNullable<int>
Andrew