Nullable <int> vs. int? - C'è qualche differenza?


93

Apparentemente Nullable<int>e int?hanno un valore equivalente. Ci sono motivi per sceglierne uno rispetto all'altro?

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

Risposte:


134

Nessuna differenza.

int?è solo una scorciatoia per Nullable<int>, che a sua volta è l'abbreviazione di Nullable<Int32>.

Il codice compilato sarà esattamente lo stesso di quello che scegli di utilizzare.


1
Purtroppo ci sono alcuni casi d'angolo in cui ciò non è strettamente vero. Vedi questa risposta .
qqbenq

22

Il ?modulo è solo una scorciatoia per il tipo completo. La preferenza personale è l'unico motivo per scegliere l'uno sull'altro.

Dettagli completi qui .

La sintassi T?è una scorciatoia per Nullable<T>, dove Tè un tipo di valore. Le due forme sono intercambiabili.


18

Mentre Sono completamente d'accordo che nella maggior parte dei casi sono gli stessi, di recente ho sono imbattuto in una situazione, quando v'è una differenza tra i due. Per i dettagli cruenti vedi questa domanda , ma per darti un rapido esempio qui:

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
}

La prima riga fornisce i seguenti messaggi di errore:

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

Se sei curioso di sapere il motivo esatto di questo, ti consiglio vivamente di controllare la domanda già collegata , ma il problema di base è che nella fase di parsing dopo un is(o un as) operatore, quando affrontiamo un ?token controlliamo se il successivo token può essere interpretato come un operatore unario ( &potrebbe essere uno) e in tal caso: al parser non interessa la possibilità che il ?token sia un modificatore di tipo, usa semplicemente il tipo prima di esso e analizzerà il resto come se ?token erano un operatore ternario (quindi l'analisi fallirà).

Quindi, sebbene in generale int?e Nullable<int>siano intercambiabili, ci sono alcuni casi d'angolo in cui producono risultati completamente diversi, a causa di come il parser vede il tuo codice.


2
Il primo caso, testè fissato con una parentesi, quindi var test = (a is int?) & b;. Può anche essere fissato con var test = a is int? && b;, e dato che bè un parametro di valore semplice (senza effetti collaterali sulla valutazione) sembra strano preferire &sopra &&.
Jeppe Stig Nielsen

In quella particolare sintassi, ?è un carattere chiave.
Pete Garafano

Vedi la domanda e la risposta collegate, i tuoi commenti sono tutti indirizzati lì :) Ho appena aggiunto queste informazioni qui, poiché ho ritenuto che fossero rilevanti, poiché mettono in risalto una differenza tra le due forme e dimostrano che non è solo zucchero sintattico
qqbenq

Jeppe ha ragione. Non sta compilando perché interpreta int?come un'operazione ternaria ( var test = a is int? <return if true> : <return if false>), non un int nullable.
Levi Fuller

1
@LeviFuller (continua) Vedere la documentazione per questi particolari boolsovraccarichi. Questi sono operatori logici booleani (il &for bool) e operatori logici condizionali booleani (il &&for bool). Notare come la prima di queste sottosezioni sia chiaramente denominata logica . Ricorda, in C # non ci sono conversioni ("cast") tra booli tipi numerici e!
Jeppe Stig Nielsen

6

Apparentemente c'è una differenza tra i due quando si utilizza la generazione di Entity Framework (EF) code-first:

Quando la tua entità contiene una proprietà dichiarata come:

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

EF non genererà una proprietà nullable e dovrai forzare il generatore a renderlo nullable in questo modo:

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

D'altra parte, se dichiari la tua entità come:

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

il generatore EF genererà una proprietà nullable con un campo nullable nella tabella di database corrispondente.


2
È davvero un peccato.
siride

8
Ciò suggerisce che hai qualche altra Nullabledefinizione da qualche parte, perché con il built-in Nullable<T>, non è possibile per EF vedere la differenza tra i due. Anche se i ragazzi di EF volessero trattarli in modo diverso, non potrebbero.

1
Qualcuno ha confermato che è così? (solo un po 'cauto a causa dei voti negativi)
RayLoveless

@ RayL No, non è questo il caso. Questa risposta non è corretta e, come ha sottolineato hvd, impossibile.
Scarpa

1
Considerando che il codice EF viene generato utilizzando modelli di codice, ciò potrebbe essere effettivamente possibile. La mia risposta si basa sulla mia esperienza e la modifica che ho suggerito ha risolto il problema che stavo riscontrando. Inoltre, sembra che alcune persone abbiano scoperto che è davvero così sulla base dei voti positivi.
Maciej

2

Nullable è un tipo generico, ma int? non è.

Ci sono alcuni scenari in cui Nullable dovrebbe essere usato su int?

per esempio: qui non puoi sostituire Nullable con int?

come puoi cambiare il codice sottostante senza usare 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
Il che potrebbe essere importante se la domanda riguardava tipi generici, ma la domanda ha specificato int, quindi non Nullable<T>èNullable<int>
Andrew
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.