Tại sao điều này không biên dịch?
int? number = true ? 5 : null;
Loại biểu thức điều kiện không thể được xác định do không có chuyển đổi ngầm giữa 'int' và <null>
Tại sao điều này không biên dịch?
int? number = true ? 5 : null;
Loại biểu thức điều kiện không thể được xác định do không có chuyển đổi ngầm giữa 'int' và <null>
Câu trả lời:
Spec (§7.14) nói rằng cho biểu thức điều kiện b ? x : y
, có ba khả năng, một trong hai x
và y
cả hai đều có một loại và một số điều kiện tốt được đáp ứng, chỉ là một trong x
và y
có một loại và một số điều kiện tốt được đáp ứng, hoặc một lỗi thời gian biên dịch xảy ra Ở đây, "một số điều kiện tốt" có nghĩa là có thể chuyển đổi nhất định, chúng tôi sẽ đi vào chi tiết bên dưới.
Bây giờ, hãy chuyển sang phần nguyên bản của thông số kỹ thuật:
Nếu chỉ có một
x
vày
có một loại, và cả haix
vày
hoàn toàn có thể chuyển đổi thành loại đó, thì đó là loại biểu thức điều kiện.
Vấn đề ở đây là
int? number = true ? 5 : null;
chỉ một trong những kết quả có điều kiện có một loại. Dưới đây x
là một int
chữ, và y
là null
mà không có một loại và null
không phải là mặc nhiên chuyển đổi thành một int
1 . Do đó, "một số điều kiện tốt" không được đáp ứng và xảy ra lỗi thời gian biên dịch.
Có được hai cách xung quanh này:
int? number = true ? (int?)5 : null;
Ở đây chúng ta vẫn còn trong trường hợp chỉ có một x
và y
có một loại. Lưu ý rằng null
vẫn không có một loại chưa trình biên dịch sẽ không có bất kỳ vấn đề với điều này bởi vì (int?)5
và null
cả hai đều mặc nhiên chuyển đổi thành int?
(§6.1.4 và §6.1.5).
Một cách khác rõ ràng là:
int? number = true ? 5 : (int?)null;
nhưng bây giờ chúng ta phải đọc một mệnh đề khác trong thông số kỹ thuật để hiểu tại sao điều này lại ổn:
Nếu
x
có loạiX
vày
có loạiY
thì
Nếu một chuyển đổi ngầm định (§6.1) tồn tại từ
X
sangY
, nhưng không phải từY
đếnX
, thì đóY
là loại biểu thức điều kiện.Nếu một chuyển đổi ngầm định (§6.1) tồn tại từ
Y
sangX
, nhưng không phải từX
đếnY
, thì đóX
là loại biểu thức điều kiện.Mặt khác, không có loại biểu thức nào có thể được xác định và xảy ra lỗi thời gian biên dịch.
Đây x
là loại int
và y
là loại int?
. Không có chuyển đổi ngầm định từ int?
sang int
, nhưng có một chuyển đổi ngầm định từ int
thành int?
nên loại biểu thức là int?
.
1 : Lưu ý thêm rằng loại phía bên trái bị bỏ qua trong việc xác định loại biểu thức điều kiện, một nguồn gây nhầm lẫn phổ biến ở đây.
new int?()
ở chỗ (int?)null
.
DateTime
, khi nó không bắt buộc(DateTime?)
null
không có bất kỳ loại nhận dạng nào - nó chỉ cần một chút kích thích để làm cho nó hạnh phúc:
int? number = true ? 5 : (int?)null;
int? number = true ? 5 : null as int?;
int? number = true ? 5 : (int?)null;
và int? number = true ? (int?)5 : null;
cả biên dịch !! Cào, cào
Như những người khác đã đề cập, 5 là một int
, và null
không thể được chuyển đổi hoàn toàn thành int
.
Dưới đây là các cách khác để khắc phục sự cố:
int? num = true ? 5 : default(int?);
int? num = true ? 5 : new int?();
int? num = true ? 5 : null as int?;
int? num = true ? 5 : (int?)null;
int? num = true ? (int?)5 : null;
int? num = true ? 5 as int? : null;
int? num = true ? new int?(5) : null;
Ngoài ra, bất cứ nơi nào bạn nhìn thấy int?
, bạn cũng có thể sử dụng Nullable<int>
.
Trong blogC# 9
này hiện đã được cho phép
Mục tiêu đánh máy ?? và?
Đôi khi có điều kiện ?? và ?: biểu thức không có kiểu chia sẻ rõ ràng giữa các nhánh. Những trường hợp như vậy thất bại ngày hôm nay, nhưng C # 9.0 sẽ cho phép chúng nếu có một loại mục tiêu mà cả hai nhánh chuyển đổi thành:
Person person = student ?? customer; // Shared base type
int? result = b ? 0 : null; // nullable value type
Hoặc ví dụ của bạn:
// Allowed in C# 9.
int? number = true ? 5 : null;