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
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
Respuestas:
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.
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 deNullable<T>, dondeTes un tipo de valor. Las dos formas son intercambiables.
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.
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 &&.
?es un personaje clave.
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.
boolsobrecargas en particular . Estos son los operadores lógicos booleanos (el ¶ bool) y los operadores lógicos condicionales booleanos (el &¶ 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.
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.
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.
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;
}
}
}
Nullable<T>lo esNullable<int>