Lưu ý rằng không có lý do gì để có cảnh báo về cuộc gọi đến Console.WriteLine()
. Thuộc tính loại tham chiếu không phải là loại nullable và do đó, trình biên dịch không cần phải cảnh báo rằng nó có thể là null.
Bạn có thể lập luận rằng trình biên dịch nên cảnh báo về tham chiếu trong struct
chính nó. Điều đó có vẻ hợp lý với tôi. Nhưng, nó không. Đây có vẻ là một lỗ hổng, do khởi tạo mặc định cho các loại giá trị, nghĩa là phải luôn có một hàm tạo mặc định (không tham số), luôn luôn chỉ ra tất cả các trường (null cho trường loại tham chiếu, số 0 cho kiểu số, v.v. ).
Tôi gọi nó là một lỗ hổng, bởi vì trong lý thuyết, các giá trị tham chiếu không thể rỗng nên trên thực tế luôn luôn là không rỗng! Tât nhiên. :)
Lỗ hổng này dường như được giải quyết trong bài viết trên blog này: Giới thiệu các loại tham chiếu không có giá trị trong C #
Tránh null cho đến nay, các cảnh báo là về việc bảo vệ null trong các tài liệu tham khảo nullable khỏi bị hủy đăng ký. Mặt khác của đồng tiền là để tránh có tất cả các giá trị rỗng trong các tài liệu tham khảo không thể hoàn thành.
Có một vài cách Null giá trị có thể đi vào cuộc sống, và hầu hết trong số đó là cảnh báo trị giá khoảng, trong khi một vài trong số họ sẽ gây ra một “biển cảnh báo” có nghĩa là tốt hơn để tránh:
...
- Sử dụng hàm tạo mặc định của một cấu trúc có một trường loại tham chiếu không thể hoàn thành. Cái này là lén lút, vì hàm tạo mặc định (không có cấu trúc) thậm chí có thể được sử dụng ngầm ở nhiều nơi. Có lẽ tốt hơn là không cảnh báo [nhấn mạnh của tôi - PD] , nếu không, nhiều kiểu cấu trúc hiện có sẽ trở nên vô dụng.
Nói cách khác, vâng, đây là một lỗ hổng, nhưng không, nó không phải là một lỗi. Các nhà thiết kế ngôn ngữ nhận thức được điều đó, nhưng đã chọn loại bỏ kịch bản này ra khỏi các cảnh báo, bởi vì nếu không thì sẽ không thực tế khi đưa ra cách struct
khởi tạo.
Lưu ý rằng điều này cũng phù hợp với triết lý rộng hơn đằng sau tính năng này. Từ cùng một bài viết:
Vì vậy, chúng tôi muốn nó phàn nàn về mã hiện tại của bạn. Nhưng không đáng ghét. Đây là cách chúng tôi sẽ cố gắng để tấn công sự cân bằng đó:
...
- Không có sự an toàn null được đảm bảo [nhấn mạnh của tôi - PD] , ngay cả khi bạn phản ứng và loại bỏ tất cả các cảnh báo. Có nhiều lỗ hổng trong phân tích bởi sự cần thiết, và cũng có một số do sự lựa chọn.
Đến điểm cuối cùng: Đôi khi, một cảnh báo là điều chính xác về việc làm, nhưng sẽ kích hoạt mọi lúc trên mã hiện có, ngay cả khi nó thực sự được viết theo cách an toàn không có giá trị. Trong những trường hợp như vậy, chúng tôi sẽ sai về phía thuận tiện, không chính xác. Chúng ta không thể mang lại một biển cảnh báo trên YouTube về mã hiện có: quá nhiều người sẽ tắt các cảnh báo và không bao giờ được hưởng lợi từ nó.
Cũng lưu ý rằng vấn đề tương tự này tồn tại với các mảng tham chiếu danh nghĩa không thể rỗng (ví dụ string[]
). Khi bạn tạo mảng, tất cả các giá trị tham chiếu là null
, nhưng điều này là hợp pháp và sẽ không tạo ra bất kỳ cảnh báo nào.
Rất nhiều để giải thích lý do tại sao mọi thứ là như vậy. Sau đó, câu hỏi trở thành, phải làm gì về nó? Điều đó chủ quan hơn rất nhiều và tôi không nghĩ có câu trả lời đúng hay sai. Mà nói…
Cá nhân tôi sẽ đối xử với struct
các loại của tôi trên cơ sở từng trường hợp. Đối với những người mà ý định thực sự là một loại tham chiếu vô giá trị, tôi sẽ áp dụng ?
chú thích. Nếu không, tôi sẽ không.
Về mặt kỹ thuật, mọi giá trị tham chiếu trong một struct
nên là "nullable", nghĩa là bao gồm ?
chú thích nullable với tên loại. Nhưng cũng như nhiều tính năng tương tự (như async / await trong C # hoặc const
trong C ++), điều này có khía cạnh "lây nhiễm", trong đó bạn sẽ cần ghi đè chú thích đó sau (với !
chú thích) hoặc bao gồm kiểm tra null rõ ràng hoặc chỉ bao giờ gán giá trị đó cho một biến loại tham chiếu nullable khác.
Đối với tôi, điều này đánh bại rất nhiều mục đích cho phép các loại tham chiếu nullable. Vì các thành viên của các struct
loại như vậy sẽ yêu cầu xử lý trường hợp đặc biệt vào một lúc nào đó, và vì cách duy nhất để thực sự xử lý an toàn trong khi vẫn có thể sử dụng các loại tham chiếu không null là đặt séc null ở mọi nơi bạn sử dụng struct
, tôi cảm thấy rằng đó là một lựa chọn triển khai hợp lý để chấp nhận rằng khi mã khởi tạo struct
, đó là trách nhiệm của mã đó để thực hiện chính xác và đảm bảo rằng thành viên loại tham chiếu không null thực tế được khởi tạo thành giá trị không null.
Điều này có thể được hỗ trợ bằng cách cung cấp một phương tiện khởi tạo "chính thức", chẳng hạn như một hàm tạo không mặc định (nghĩa là một hàm có tham số) hoặc phương thức xuất xưởng. Vẫn sẽ có rủi ro khi sử dụng hàm tạo mặc định hoặc hoàn toàn không có hàm tạo (như trong phân bổ mảng), nhưng bằng cách cung cấp một phương tiện thuận tiện để khởi tạo struct
chính xác, điều này sẽ khuyến khích mã sử dụng nó để tránh các tham chiếu null trong không biến nullable.
Điều đó nói rằng, nếu những gì bạn muốn là 100% an toàn đối với các loại tài liệu tham khảo nullable, sau đó rõ ràng cách tiếp cận chính xác cho rằng mục tiêu cụ thể là phải luôn luôn chú thích mọi thành viên kiểu tham chiếu trong một struct
với ?
. Điều này có nghĩa là mọi trường và mọi thuộc tính được triển khai tự động, cùng với bất kỳ phương thức hoặc thuộc tính getter nào trả về trực tiếp các giá trị đó hoặc sản phẩm của các giá trị đó. Sau đó, mã tiêu thụ sẽ cần bao gồm kiểm tra null hoặc toán tử tha thứ null tại mọi điểm nơi các giá trị đó được sao chép thành các biến không null.