Nullable <int> проти int? - Чи є якась різниця?


93

Мабуть 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) оператора, коли ми стикаємося з ?маркером, ми перевіряємо, чи буде наступним маркер можна інтерпретувати як одинарний оператор ( &може бути і одним), і якщо так: синтаксичний аналізатор не дбає про можливість того, щоб ?маркер був модифікатором типу, він просто використовує тип перед ним, а решту аналізуватиме так, ніби ?лексеми були потрійним оператором (таким чином, аналіз не вдасться).

Отже, хоча загалом int?і Nullable<int>є взаємозамінними, є деякі кутові випадки, коли вони дають абсолютно різні результати, через те, як парсер бачить ваш код.


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

У цьому конкретному синтаксисі ?є ключовим символом.
Піт Гарафано

Дивіться пов’язане запитання та відповідь, всі ваші коментарі там розглядаються :) Я щойно додав цю інформацію сюди, оскільки вважав її доречною, оскільки вона виявляє різницю між цими двома формами і доводить, що це не просто синтаксичний цукор
qqbenq

Джеппе має рацію. Це не компіляція, оскільки вона трактується int?як потрійна операція ( var test = a is int? <return if true> : <return if false>), а не як нульовий int.
Леві Фуллер

1
@LeviFuller (продовження) Див. Документацію щодо цих конкретних boolперевантажень. Це логічні логічні оператори ( &for bool) та логічні умовні логічні оператори ( &&for bool). Зверніть увагу, як перший із цих підрозділів чітко названий логічним . Пам'ятайте, що в C # немає перетворень ("приводів") між boolі числовими типами!
Jeppe Stig Nielsen

6

Очевидно, між цими двома різницями є використання генерації Entity Framework (EF):

Коли ваша сутність містить властивість, заявлену як:

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

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

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 генерує властивість, що допускає нульове значення з полем, що допускає нульове значення у відповідній таблиці бази даних.


2
Це справді прикро.
siride

8
Це означає, що у вас є десь інше Nullableвизначення, оскільки завдяки вбудованому Nullable<T>EF не може побачити різницю між ними. Навіть якби люди з ЕФ хотіли поводитися з ними інакше, вони не могли.

1
Хтось підтвердив, що це так? (трохи обережний через негативні голоси)
RayLoveless

@RayL Ні, це не так. Ця відповідь не є правильною, і, як зазначив hvd, неможлива.
Взуття

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.