Nullable <int> против int? - Есть разница?


94

Видимо Nullable<int>и int?равнозначны по стоимости. Есть ли причины выбрать одно из них?

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

Ответы:


135

Нет разницы.

int?это просто сокращение для Nullable<int>, которое само является сокращением для Nullable<Int32>.

Скомпилированный код будет точно таким же, какой бы вы ни выбрали.


1
К сожалению, в некоторых случаях это не совсем так. Смотрите этот ответ .
— qqbenq

22

?Форма просто сокращение для полного типа. Личные предпочтения - единственная причина предпочесть одно другому.

Подробности здесь .

Синтаксис T?является сокращением для Nullable<T>, где T- тип значения. Эти две формы взаимозаменяемы.


18

Хотя я полностью согласен с тем, что в большинстве случаев они одинаковы, недавно я столкнулся с ситуацией, когда между ними есть разница. Подробности см. В этом вопросе , но вот краткий пример:

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
}

Первая строка дает следующие сообщения об ошибках:

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

Если вам интересно узнать точную причину этого, я действительно рекомендую вам проверить уже связанный вопрос , но основная проблема заключается в том, что на этапе синтаксического анализа после is(или as) оператора, когда мы сталкиваемся с ?токеном, мы проверяем, будет ли следующий токен можно интерпретировать как унарный оператор ( &может быть таковым), и если так: синтаксический анализатор не заботится о возможности того, что ?токен является модификатором типа, он просто использует тип перед ним и будет анализировать остальные, как если бы ?token были тернарным оператором (таким образом, синтаксический анализ не удастся).

Таким образом, в то время как в целом int?и Nullable<int>являются взаимозаменяемыми, есть некоторые частные случаи , когда они производят совершенно разные результаты, так как анализатор видит ваш код.


2
Первый случай test,, фиксируется круглыми скобками, поэтому var test = (a is int?) & b;. Может быть исправлены с var test = a is int? && b;, и при условии , что bявляется параметром простого значения (отсутствие побочных эффектов по оценке), кажется странным, предпочитает &более &&.
— Jeppe Stig Nielsen

В этом конкретном синтаксисе ?- ключевой символ.
— Pete Garafano

См. Связанный вопрос и ответ, все ваши комментарии адресованы там :) Я только что добавил эту информацию сюда, так как считаю ее актуальной, поскольку она выявляет разницу между двумя формами и доказывает, что это не просто синтаксический сахар
— qqbenq

Джепп прав. Он не компилируется, потому что интерпретируется int?как тернарная операция ( var test = a is int? <return if true> : <return if false>), а не как int, допускающий значение NULL.
— Леви Фуллер,

1
@LeviFuller (продолжение) См. Документацию по этим конкретным boolперегрузкам. Это булевы логические операторы ( &for bool) и логические условные логические операторы ( &&for bool). Обратите внимание, что первый из этих подразделов четко назван логическим . Помните, что в C # нет преобразований ("приведений") между boolчисловыми типами и!
— Йеппе Стиг Нильсен

6

Очевидно, существует разница между ними при использовании генерации Entity Framework (EF) с первым кодом:

Когда ваша сущность содержит свойство, объявленное как:

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

EF не будет генерировать свойство, допускающее значение NULL, и вам придется заставить генератор сделать его допускающим значение NULL следующим образом:

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

С другой стороны, если вы объявите свою сущность как:

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

генератор EF создаст свойство, допускающее значение NULL, с полем, допускающим значение NULL, в соответствующей таблице базы данных.


2
Это действительно прискорбно.
— siride 05

8
Это говорит о том, что у вас есть какое-то другое Nullableопределение, потому что со встроенным Nullable<T>EF не может увидеть разницу между ними. Даже если бы люди из EF хотели относиться к ним по-другому, они не могли.

1
Кто-то подтвердил, что это так? (немного осторожно из-за отрицательных голосов)
— RayLoveless

@RayL Нет, дело не в этом. Этот ответ неверен и, как указывает hvd, невозможен.
— Shoe

1
Учитывая, что код EF создается с использованием шаблонов кода, это действительно возможно. Мой ответ основан на моем опыте, и предложенное мной изменение устранило мою проблему. Кроме того, похоже, что некоторые люди обнаружили, что это действительно так, на основе голосов за.
— Maciej

2

Nullable - это общий тип, но int? не является.

Есть несколько сценариев, в которых Nullable следует использовать вместо int?

например: здесь вы не можете заменить Nullable на int?

как вы можете изменить приведенный ниже код без использования 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
Что может иметь значение, если вопрос касается общих типов, но в вопросе указано int, поэтому это не Nullable<T>такNullable<int>
— Эндрю
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.