Nullable <int> so với int? - Có gì khác biệt không?


93

Rõ ràng Nullable<int>và int?có giá trị tương đương. Có lý do nào để chọn cái này hơn cái kia không?

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

Câu trả lời:


135

Không khác nhau.

int?chỉ là viết tắt cho Nullable<int>, bản thân nó là viết tắt của Nullable<Int32>.

Mã đã biên dịch sẽ giống hệt như bất kỳ mã nào bạn chọn sử dụng.


1
Thật không may, có một số trường hợp góc khi điều này không hoàn toàn đúng. Hãy xem câu trả lời này .
— qqbenq

22

Biểu ?mẫu chỉ là cách viết tắt của loại đầy đủ. Sở thích cá nhân là lý do duy nhất để chọn cái này hơn cái kia.

Chi tiết đầy đủ tại đây .

Cú pháp T?là viết tắt của Nullable<T>, đâu Tlà kiểu giá trị. Hai hình thức có thể thay thế cho nhau.


18

Trong khi tôi hoàn toàn đồng ý rằng trong nhiều trường hợp họ đều giống nhau, tôi vừa đi qua một tình huống, khi có là một sự khác biệt giữa hai. Để biết thêm chi tiết, hãy xem câu hỏi này , nhưng để cung cấp cho bạn một ví dụ nhanh ở đây:

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
}

Dòng đầu tiên đưa ra các thông báo lỗi sau:

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

Nếu bạn tò mò về lý do chính xác cho điều này, tôi thực sự khuyên bạn nên kiểm tra câu hỏi đã được liên kết , nhưng vấn đề cơ bản là trong giai đoạn phân tích cú pháp sau một is(hoặc một as) toán tử, khi chúng ta gặp một ?mã thông báo, chúng ta sẽ kiểm tra xem tiếp theo mã thông báo có thể được hiểu là toán tử một ngôi ( &có thể là một) và nếu vậy: trình phân tích cú pháp không quan tâm đến khả năng ?mã thông báo là một công cụ sửa đổi kiểu, nó chỉ sử dụng kiểu trước nó và sẽ phân tích cú pháp phần còn lại như thể ?mã thông báo là một toán tử bậc ba (do đó phân tích cú pháp sẽ không thành công).

Vì vậy, trong khi nói chung int?và Nullable<int>có thể hoán đổi cho nhau, có một số trường hợp góc khi chúng tạo ra các kết quả hoàn toàn khác nhau, do cách trình phân tích cú pháp nhìn thấy mã của bạn.


2
Trường hợp đầu tiên test, được cố định bằng dấu ngoặc đơn, vì vậy var test = (a is int?) & b;. Cũng có thể được sửa với var test = a is int? && b;, và cho rằng đó blà một tham số giá trị đơn giản (không có tác dụng phụ khi đánh giá) thì có vẻ lạ hơn là thích &hơn &&.
— Jeppe Stig Nielsen

Trong cú pháp cụ thể đó, ?là một ký tự chính.
— Pete Garafano

Xem câu hỏi và câu trả lời được liên kết, nhận xét của bạn đều được giải quyết ở đó :) Tôi chỉ thêm thông tin này ở đây, vì tôi cảm thấy nó có liên quan, vì nó tạo ra sự khác biệt giữa hai hình thức và chứng minh rằng nó không chỉ là đường cú pháp
— qqbenq

Jeppe đúng. Nó không biên dịch vì nó đang diễn giải int?như một phép toán bậc ba ( var test = a is int? <return if true> : <return if false>), không phải là một int nullable.
— Levi Fuller

1
@LeviFuller (tiếp theo) Xem tài liệu về các trường hợp boolquá tải cụ thể này . Đây là các toán tử logic Boolean ( &for bool) và toán tử logic có điều kiện Boolean ( &&for bool). Lưu ý cách phần đầu tiên trong số các phần phụ này được đặt tên logic rõ ràng . Hãy nhớ rằng, trong C # không có chuyển đổi ("phôi") giữa boolvà kiểu số!
— Jeppe Stig Nielsen

6

Rõ ràng là có sự khác biệt giữa hai cách này khi sử dụng tạo Khung thực thể đầu tiên (EF):

Khi thực thể của bạn chứa một thuộc tính được khai báo như:

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

EF sẽ không tạo thuộc tính nullable và bạn sẽ phải buộc trình tạo làm cho nó có thể nullable như sau:

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

Mặt khác, nếu bạn khai báo pháp nhân của mình như:

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

trình tạo EF sẽ tạo thuộc tính nullable với trường nullable trong bảng cơ sở dữ liệu tương ứng.


2
Điều đó thực sự đáng tiếc.
— siride

8
Điều đó cho thấy bạn có một số Nullableđịnh nghĩa khác ở đâu đó, bởi vì với tính năng tích hợp Nullable<T>, EF không thể thấy sự khác biệt giữa hai định nghĩa này. Ngay cả khi các thành viên EF muốn đối xử khác với họ, họ không thể.

1
Có ai đó đã xác nhận đây là trường hợp? (chỉ cần thận trọng một chút vì số phiếu tiêu cực)
— RayLoveless

@RayL Không, đây không phải là trường hợp. Câu trả lời này là không đúng và như hvd đã chỉ ra, không thể.
— Giày

1
Xem xét rằng mã EF được tạo bằng cách sử dụng các mẫu mã, điều này trên thực tế có thể có. Câu trả lời của tôi dựa trên kinh nghiệm của tôi và thay đổi mà tôi đề xuất đã khắc phục sự cố mà tôi đang gặp phải. Ngoài ra, có vẻ như một số người nhận thấy rằng nó thực sự là trường hợp dựa trên số phiếu ủng hộ.
— Maciej

2

Nullable là một kiểu chung, nhưng int? không phải.

Có một số trường hợp mà Nullable nên được sử dụng trên int?

ví dụ: ở đây bạn không thể thay thế Nullable bằng int?

Làm thế nào bạn có thể thay đổi mã bên dưới mà không sử dụng 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
Mà có thể có vấn đề nếu câu hỏi được hỏi về các loại chung chung, nhưng câu hỏi đã quy định int, vì vậy nó không Nullable<T>nóNullable<int>
— Andrew
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookie và Chính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.