Nullable <int> vs. int? - ¿Hay alguna diferencia?

93

Aparentemente Nullable<int>y int?son equivalentes en valor. ¿Hay alguna razón para elegir una u otra?

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

Respuestas:

135

Ninguna diferencia.

int?es una abreviatura de Nullable<int>, que en sí misma es una abreviatura de Nullable<Int32>.

El código compilado será exactamente el mismo, cualquiera que elija utilizar.

LukeH
fuente
1
Desafortunadamente, hay algunos casos extremos en los que esto no es estrictamente cierto. Vea esta respuesta .
qqbenq
22

El ?formulario es solo una abreviatura del tipo completo. La preferencia personal es la única razón para elegir uno sobre el otro.

Detalles completos aquí .

La sintaxis T?es una abreviatura de Nullable<T>, donde Tes un tipo de valor. Las dos formas son intercambiables.

Steve Townsend
fuente
18

Si bien estoy totalmente de acuerdo en que en la mayoría de los casos son los mismos, hace poco encontré con una situación, cuando no es una diferencia entre los dos. Para los detalles sangrientos, vea esta pregunta , pero para darle un ejemplo rápido aquí:

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 primera línea muestra los siguientes mensajes de error:

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

Si tiene curiosidad sobre la razón exacta de esto, realmente le recomiendo que revise la pregunta ya vinculada , pero el problema básico es que en la fase de análisis después de un is(o un as) operador, cuando nos enfrentamos a un ?token, verificamos si el siguiente token se puede interpretar como un operador unario ( &podría ser uno) y, de ser así: al analizador no le importa la posibilidad de que el ?token sea un modificador de tipo, simplemente usa el tipo anterior y analizará el resto como si el ?token era un operador ternario (por lo tanto, el análisis fallará).

Entonces, aunque en general int?y Nullable<int>son intercambiables, hay algunos casos extremos en los que producen resultados completamente diferentes, debido a cómo el analizador ve su código.

qqbenq
fuente
2
El primer caso, testse fija entre paréntesis, entonces var test = (a is int?) & b;. También se puede fijar con var test = a is int? && b;, y dado que bes un parámetro de valor simple (sin efectos secundarios sobre la evaluación) que parece extraño a preferir &más &&.
Jeppe Stig Nielsen
En esa sintaxis en particular, ?es un personaje clave.
Pete Garafano
Vea la pregunta y respuesta vinculadas, todos sus comentarios se abordan allí :) Acabo de agregar esta información aquí, ya que sentí que es relevante, ya que resalta una diferencia entre las dos formas y demuestra que no es solo azúcar sintáctico
qqbenq
Jeppe tiene razón. No está compilando porque se interpreta int?como una operación ternaria ( var test = a is int? <return if true> : <return if false>), no como un int que acepta valores NULL.
Levi Fuller
1
@LeviFuller (continuación) Consulte la documentación para estas boolsobrecargas en particular . Estos son los operadores lógicos booleanos (el &para bool) y los operadores lógicos condicionales booleanos (el &&para bool). Observe cómo la primera de estas subsecciones se llama claramente lógica . Recuerde, en C # no hay conversiones ("conversiones") entre booly tipos numéricos.
Jeppe Stig Nielsen
6

Aparentemente, hay una diferencia entre los dos cuando se usa la generación de Entity Framework (EF) de código primero:

Cuando su entidad contiene una propiedad declarada como:

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

EF no generará una propiedad anulable y tendrá que forzar al generador para que sea anulable así:

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

Por otro lado, si declara su entidad como:

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

el generador de EF generará una propiedad anulable con un campo anulable en la tabla de base de datos correspondiente.

Maciej
fuente
2
Eso es realmente lamentable.
siride
8
Eso sugiere que tiene alguna otra Nullabledefinición en alguna parte, porque con el incorporado Nullable<T>, EF no puede ver la diferencia entre los dos. Incluso si la gente de EF quisiera tratarlos de manera diferente, no podrían.
1
¿Alguien ha confirmado que este es el caso? (solo un poco cauteloso debido a los votos negativos)
RayLoveless
@RayL No, este no es el caso. Esta respuesta no es correcta y, como señaló hvd, imposible.
Zapato
1
Teniendo en cuenta que el código EF se genera mediante plantillas de código, esto puede ser posible. Mi respuesta se basa en mi experiencia y el cambio que sugerí solucionó el problema que estaba teniendo. Además, parece que algunas personas descubrieron que, de hecho, es así basándose en los votos positivos.
Maciej
2

Nullable es un tipo genérico, pero int? no es.

¿Hay algunos escenarios en los que Nullable debería usarse sobre int?

por ejemplo: aquí no se puede reemplazar Nullable con int?

¿Cómo puede cambiar el siguiente código sin usar 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;
      }
   }
}
Rajes
fuente
3
Lo que podría importar si la pregunta fuera sobre tipos genéricos, pero la pregunta ha especificado int, por lo que no Nullable<T>lo esNullable<int>
Andrew