2010-04-09 30 views
21

Các mã sau đây không biên dịch:Tại sao null cần một loại diễn viên rõ ràng ở đây?

//int a = ... 
int? b = (int?) (a != 0 ? a : null); 

Để biên dịch, nó cần phải được thay đổi để

int? b = (a != 0 ? a : (int?) null); 

Kể từ khi cả hai b = nullb = a là hợp pháp, điều này không có ý nghĩa với tôi .

Tại sao chúng ta phải bỏ null vào một int? và tại sao chúng ta không thể đơn giản cung cấp một loại diễn viên rõ ràng cho toàn bộ biểu thức (mà tôi biết là có thể trong các trường hợp khác)?

+8

Tôi chỉ nghĩ trình biên dịch không thích bạn hỏi quá nhiều câu hỏi. Tôi có nghĩa là nhìn, bạn có như 3 người trong số họ trong một dòng! – David

+2

Điều này sẽ trả lời câu hỏi của bạn về lý do: http://stackoverflow.com/questions/2215745/conditional-operator-cannot-cast-implicitly/2215959#2215959. Câu hỏi này không phải là * khá * một bản sao của câu hỏi đó, nhưng lý do vẫn như cũ. –

+1

Lưu ý rằng 'int? b = a! = 0? (int?) a: null; 'cũng hoạt động –

Trả lời

18

Từ chương 7.13 của C Thông số kỹ thuật # Ngôn Ngữ:

Các toán hạng thứ hai và thứ ba của: kiểm soát hành kiểu của biểu thức điều kiện. Cho X và Y là các loại toán hạng thứ hai và thứ ba. Sau đó,

  • Nếu X và Y cùng loại, thì đây là loại biểu thức có điều kiện.
  • Nếu không, nếu chuyển đổi ẩn (§6.1) tồn tại từ X thành Y, nhưng không phải từ Y thành X, thì Y là loại biểu thức có điều kiện.
  • Nếu không, nếu chuyển đổi ẩn (§6.1) tồn tại từ Y thành X, nhưng không phải từ X thành Y, thì X là loại biểu thức có điều kiện.
  • Nếu không, không thể xác định loại biểu thức nào và xảy ra lỗi biên dịch.

Trong trường hợp của bạn, không có chuyển đổi ẩn từ int thành null hoặc ngược lại. Dàn diễn viên của bạn giải quyết được vấn đề, int có thể chuyển đổi thành int?

+0

Ah, tôi hiểu rồi. Tôi sẽ không nghĩ rằng cả hai biểu thức cần phải có cùng một loại, miễn là cả hai đều ngầm đúc vào loại được chỉ định - điều gì sẽ xảy ra nếu tôi nói 'Animal animal = (điều kiện? New Cat(): new Dog ()) '? –

+1

Sau đó, bạn cũng sẽ gặp lỗi trình biên dịch. (Trừ khi bạn bỏ hai bên sang 'Động vật') – SLaks

+1

Phía bên trái của câu lệnh gán không ảnh hưởng đến loại biểu thức. Mèo không được chuyển đổi hoàn toàn cho chó, vợ tôi khăng khăng. –

1

đó là vì khi bạn sử dụng loại ký hiệu đó, cả hai thành viên phải cùng loại, vì vậy bạn phải nói rõ ràng "thành viên này là một int?".

có rõ không?

+0

-1: chúng không cần phải thuộc cùng một loại, chỉ cần có thể chuyển sang loại khác: xem ở trên, @nobugz và @Vlad. – ANeves

+0

@ srpt, tôi cũng muốn bỏ phiếu, nhưng sau đó tôi thấy bạn đã không thực sự downvote và undid downvote của tôi. –

+0

=/Tôi làm gì? * [tiếng la hét] * Curses! Tôi đã xóa bỏ ý nghĩ vì tôi đã thay đổi ý định, nhưng quên chỉnh sửa '-1:' khi bắt đầu nhận xét - xin lỗi! (Tôi đã thay đổi ý định bởi vì đó không phải là câu trả lời sai, không chính xác hoặc rõ ràng.) – ANeves

5

Cả hai lựa chọn thay thế của nhà điều hành ?: phải cùng loại. Nếu không, trình biên dịch không thể suy ra loại của toàn bộ biểu thức có điều kiện.

null không phải là int, vì vậy bạn cần cung cấp gợi ý cho trình biên dịch rằng loại kết quả là int?.


Chỉnh sửa: như những người khác đã chỉ ra rằng, hai loại này không cần phải giống nhau, nhưng một trong số chúng không thể chuyển sang loại khác (một loại khác sẽ là loại kết quả). Xem specs để biết thêm chi tiết.

1

Khi bạn sử dụng toán tử có điều kiện với toán hạng của các loại khác nhau, trình biên dịch sẽ kiểm tra xem một trong các loại có thể được chuyển đổi hoàn toàn sang loại khác hay không.

Nếu không phải loại nào có thể được chuyển đổi hoàn toàn sang loại khác, nó sẽ gây ra lỗi, ngay cả khi có loại thứ ba mà cả hai có thể chuyển đổi hoàn toàn. Trình biên dịch sẽ không chèn một chuyển đổi ngầm trên cả hai mặt cùng một lúc.

Trong trường hợp của bạn, cả hai intnull yêu cầu chuyển đổi ngầm để trở thành int?, do đó, nó không hoạt động.
Bạn cần thay đổi mã của mình để một bên là int? và bên kia có thể được chuyển đổi hoàn toàn thành int?. Cách simplested để làm điều này là để thay thế null với new int?(), như thế này:

int? b = (a != 0 ? a : new int?()); 

này chỉ đòi hỏi một chuyển đổi ngầm (int để int?).

5

Bạn có thể tiết kiệm cho mình khi truyền nếu bạn sử dụng default(int?) thay vì null.

int a = 42; 
int? b = (a != 0 ? a : default(int?)); 
0

Đây là một bản sao của one câu hỏi của tôi, liên quan đến toán tử có điều kiện. Nó không phải là null, nó thực sự là :.

Câu trả lời được chấp nhận ở đó là khá tốt, không ai khác ngoài Eric Lippert, người thuộc nhóm trình biên dịch C#.

Các vấn đề liên quan