2011-09-29 13 views
10

Định nghĩa của Nullable<T> là:Tại sao tôi không thể viết Nullable <Nullable <int>>?

[SerializableAttribute] 
public struct Nullable<T> where T : struct, new() 

Ràng buộc where T : struct ngụ ý rằng T chỉ có thể là một loại giá trị. Vì vậy, tôi rất tốt hiểu rằng tôi không thể viết:

Nullable<string> a; //error. makes sense to me 

string là một loại tài liệu tham khảo, không phải là một loại giá trị. Nhưng tôi thực sự không hiểu tại sao tôi không thể viết

Nullable<Nullable<int>> b; //error. but why? 

Tại sao không được phép? Sau khi tất cả, Nullable<int> là một loại giá trị, và do đó, nó có thể được loại đối số để Nullablle<T>.

Khi tôi biên soạn nó trên ideone, nó mang lại cho lỗi này (ideone):

lỗi CS0453: '? Int' Loại phải là một kiểu giá trị không nullable để sử dụng nó như là kiểu tham số 'T' trong các loại generic hoặc phương pháp 'System.Nullable' Compilation failed: 1 lỗi (s), 0 cảnh báo

+0

Lỗi nào? – asawyer

+2

Xin lỗi, câu trả lời của tôi là sai. Câu lệnh 'new Nullable (); 'biên dịch (dẫn đến' int? 'Với giá trị null), mặc dù hàm tạo mặc định không được ghi lại. – BoltClock

+0

Và có, câu trả lời là trong lỗi mà bạn sẽ nhận được khi bạn cố gắng biên dịch mã của bạn. – BoltClock

Trả lời

5

Từ phần 4.1.10 của spec ngôn ngữ C#:

Một kiểu giá trị không nullable ngược lại là bất kỳ loại giá trị khác hơn System.Nullable<T> và nó viết tắt T? (đối với bất kỳ T), cộng với bất kỳ tham số kiểu nào bị ràng buộc là một loại giá trị không nullable (có nghĩa là, bất kỳ tham số kiểu nào có ràng buộc struct). Loại System.Nullable<T> chỉ định ràng buộc loại giá trị cho T (§10.1.5), có nghĩa là loại cơ bản của loại có thể vô hiệu hóa có thể là bất kỳ loại giá trị không null nào. Kiểu cơ bản của một kiểu nullable không thể là một kiểu nullable hoặc một kiểu tham chiếu. Ví dụ: int??string? là các loại không hợp lệ.

9

Bởi vì đó là trong C# spec (phần 4.4.4):

Nếu hạn chế là kiểu giá trị ràng buộc (struct), loại A phải đáp ứng một trong các cách sau:

  • A là một cấu trúc kiểu hoặc loại enum, nhưng không phải là loại vô hiệu. Lưu ý rằng System.ValueType và System.Enum là các kiểu tham chiếu không thỏa mãn ràng buộc này.
  • A là một tham số kiểu có ràng buộc kiểu giá trị (§10.1.5).
+0

Vui lòng mở rộng trên báo giá spec. Tôi không hoàn toàn hiểu điều đó. Tôi mới đến C#. – Nawaz

+0

Ràng buộc kiểu generic 'struct' mà bạn áp dụng cho các lớp là _specified_ như là 'tất cả các giá trị & loại enum ngoài' Nullable '', đặc biệt để dừng vòng tròn này. – thecoop

+0

@thecoop: Nó không phải là một điểm kỳ dị. Nó không phải là ràng buộc 'struct' trong tham số kiểu' Nullable', ta có thể có một 'Dictionary ' 'bao gồm một phương thức' Nullable 'TryGetValue (TKey)' mà không phải sử dụng tham số 'out'. Với 'Dictionary > myDict', sau' var it = myDict.TryGetValue ("Fred"); 'if' it.HasValue' là sai, điều đó có nghĩa là không tìm thấy khóa nào; nếu 'it.HasValue' là true nhưng' it.Value.HasValue' là false, điều đó có nghĩa là một giá trị null được lưu trữ cho khóa "Fred". Khó khăn thực sự bắt nguồn từ quyết định của MS ... – supercat

3

Từ §10.1.5 của C# 4 spec:

Các kiểu giá trị hạn chế quy định rằng một đối số kiểu sử dụng cho các tham số kiểu phải là một kiểu giá trị không nullable. Tất cả các kiểu struct, kiểu enum và tham số kiểu không có giá trị không có ràng buộc kiểu giá trị thỏa mãn ràng buộc này. Lưu ý rằng mặc dù được phân loại là một loại giá trị, một kiểu không có giá trị (§4.1.10) không thỏa mãn ràng buộc kiểu giá trị. Một tham số kiểu có ràng buộc kiểu giá trị không thể có ràng buộc của hàm tạo.

1

Như những người khác đã nói, thông số này nghiêm cấm điều này.

Đào sâu hơn, nó có giá trị nhận ra rằng bạn thể làm struct của riêng bạn mà cho phép mô hình này:

struct Nestable<T> where T : struct { /* ... */ } 

new Nestable<Nestable<int>>(); // This works just fine 

Việc cấm nullables lồng nhau không thể được thể hiện bằng cách sử dụng hệ thống kiểu có sẵn cho bạn và tôi. Nó chỉ được thực thi bởi một trường hợp đặc biệt trong trình biên dịch (CS0453).


Ngoài: Ràng buộc new() thể hiện trong câu hỏi không thực sự tồn tại trên System.Nullable<T>. Các ràng buộc new() bị cấm khi sử dụng ràng buộc struct.

CS0451: Ràng buộc 'mới()' không thể được sử dụng với 'struct' chế

Tất cả các cấu trúc hỗ trợ mặc định khởi động anyway.

+0

Theo tài liệu, không còn ràng buộc 'mới()': https://referencesource.microsoft.com/#mscorlib/system/nullable.cs – series0ne

1

Đây không phải là câu trả lời chính xác, nhưng chỉ là thức ăn cho sự suy nghĩ.

Vòng 1

Nullable<Nullable<int>> a;

CS0453 lỗi: Các loại 'int?' phải là một kiểu giá trị không nullable để sử dụng nó như là tham số 'T' trong các loại generic hoặc phương pháp 'Nullable'

Intellisense gợi ý ... Tên có thể được đơn giản hóa


Vòng 2

Nullable<int?> a;

lỗi CS0453: Loại 'int?' phải là một kiểu giá trị không nullable để sử dụng nó như là tham số 'T' trong các loại generic hoặc phương pháp 'Nullable'

Intellisense gợi ý ... Tên có thể được đơn giản hóa


Vòng 3

int?? a;

lỗi CS1519: Mã thông báo không hợp lệ '??'trong khai báo lớp học, cấu trúc hoặc thành viên giao diện

lỗi CS1525: Cụm từ biểu thức không hợp lệ' ?? '


Kết luận

int? về cơ bản chỉ là một đánh giá ngắn tay Nullable<int>, nhưng không có những điều như int?? đó là cách duy nhất tôi có thể thấy đại diện Nullable<Nullable<int>> trong ngắn tay . Plus int?? vay mượn toán tử kết hợp null, vì vậy tôi rất vui vì nó không thể thực hiện được vì nó trông đáng sợ. Hãy tưởng tượng int????????????? a; Làm thế nào vô nghĩa. Cuối cùng, vì nguồn tham chiếu cho Nullable không mang lại bất kỳ ràng buộc nào để thực thi điều này, tôi đoán là ràng buộc này đã được đưa vào CLR như một trường hợp đặc biệt khi các kiểu giá trị rỗng được đưa vào C#.