Anulável <int> vs. int? - Existe alguma diferença?

93

Aparentemente Nullable<int>e int?são equivalentes em valor. Existe alguma razão para escolher um em vez do outro?

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

Respostas:

134

Sem diferença.

int?é apenas uma abreviatura de Nullable<int>, que em si é uma abreviatura de Nullable<Int32>.

O código compilado será exatamente o mesmo que você escolher usar.

LukeH
fonte
1
Infelizmente, existem alguns casos em que isso não é estritamente verdade. Veja esta resposta .
qqbenq
22

O ?formulário é apenas uma abreviação para o tipo completo. A preferência pessoal é a única razão para escolher um em vez do outro.

Detalhes completos aqui .

A sintaxe T?é um atalho para Nullable<T>, onde Té um tipo de valor. As duas formas são intercambiáveis.

Steve Townsend
fonte
18

Embora concorde plenamente que na maioria dos casos eles são o mesmo, recentemente deparei com uma situação, quando não é a diferença entre os dois. Para os detalhes sangrentos, consulte esta pergunta , mas para dar um exemplo rápido aqui:

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
}

A primeira linha fornece as seguintes mensagens de erro:

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

Se você está curioso sobre o motivo exato para isso, eu realmente recomendo que você verifique a questãovinculada , mas o problema básico é que na fase de análise após um is(ou um as) operador, quando nos deparamos com um ?token, verificamos se o próximo token pode ser interpretado como um operador unário ( &poderia ser um) e se assim for: o analisador não se preocupa com a possibilidade de o ?token ser um modificador de tipo, ele simplesmente usa o tipo antes dele e irá analisar o resto como se o? token era um operador ternário (portanto, a análise falhará).

Portanto, embora em geral int?e Nullable<int>sejam intercambiáveis, existem alguns casos extremos em que eles produzem resultados completamente diferentes, devido à forma como o analisador vê seu código.

qqbenq
fonte
2
O primeiro caso test,, é fixado com um parêntese, portanto var test = (a is int?) & b;. Também pode ser corrigido com var test = a is int? && b;, e dado que bé um parâmetro de valor simples (sem efeitos colaterais sobre a avaliação) parece estranho a preferir &mais &&.
Jeppe Stig Nielsen
Nessa sintaxe específica, ?é um personagem-chave.
Pete Garafano
Veja a pergunta e a resposta no link, seus comentários estão todos endereçados lá :) Acabei de adicionar essa informação aqui, pois achei que é relevante, pois traz uma diferença entre as duas formas e prova que não é apenas um açúcar sintático
qqbenq
Jeppe está correto. Não está compilando porque está interpretando int?como uma operação ternária ( var test = a is int? <return if true> : <return if false>), não um int anulável.
Levi Fuller
1
@LeviFuller (continuação) Consulte a documentação para essas boolsobrecargas específicas . Estes são operadores lógicos booleanos (o &for bool) e operadores lógicos condicionais booleanos (o &&for bool). Observe como a primeira dessas subseções é claramente chamada de lógica . Lembre-se, em C # não há conversões ("casts") entre boolos tipos numéricos!
Jeppe Stig Nielsen
6

Aparentemente, há uma diferença entre os dois ao usar a geração de Entity Framework (EF) de código primeiro:

Quando sua entidade contém uma propriedade declarada como:

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

EF não irá gerar uma propriedade anulável e você terá que forçar o gerador para torná-la anulável assim:

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 outro lado, se você declarar sua entidade como:

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

o gerador EF irá gerar uma propriedade anulável com um campo anulável na tabela de banco de dados correspondente.

Maciej
fonte
2
Isso é realmente lamentável.
siride
8
Isso sugere que você tem alguma outra Nullabledefinição em algum lugar, porque com o embutido Nullable<T>, não é possível para EF ver a diferença entre os dois. Mesmo que o pessoal da EF quisesse tratá-los de maneira diferente, eles não poderiam.
1
Alguém confirmou que este é o caso? (um pouco cauteloso por causa dos votos negativos)
RayLoveless
@RayL Não, este não é o caso. Esta resposta não está correta e, como o hvd apontou, impossível.
Sapato
1
Considerando que o código EF é gerado usando modelos de código, isso pode de fato ser possível. Minha resposta é baseada na minha experiência e a mudança que sugeri corrigiu o problema que eu estava tendo. Além disso, parece que algumas pessoas descobriram que esse é realmente o caso com base nos votos positivos.
Maciej
2

Nullable é um tipo genérico, mas int? não é.

Existem alguns cenários em que Nullable deve ser usado em vez de int?

por exemplo: aqui você não pode substituir Nullable por int?

como você pode alterar o código abaixo sem 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
fonte
3
O que pode importar se a pergunta era sobre tipos genéricos, mas a pergunta especificou int, então não Nullable<T>éNullable<int>
Andrew