2011-10-10 24 views
5

Đã có nhiều câu hỏi xung quanh hỗ trợ cho các kiểu tham chiếu không thể rỗng trong .NET. Hy vọng lớn là hợp đồng mã, nhưng nó được giới hạn trong việc kiểm tra thời gian chạy cho những người có ngân sách hạn chế.Các loại tham chiếu không thể vô hiệu hóa (một lần nữa)

Đối với các cách tiếp cận khác với Hợp đồng mã, Jon Skeet đã viết một số blog post về điều này một vài năm trước đây và một trong những người nhận xét đã cung cấp một cái nhìn hữu ích NonNull struct. Điều này có vẻ giống như một cách tiếp cận tuyệt vời, và tôi có thể tưởng tượng mở rộng nó để cung cấp tất cả các loại không vô giá trị microtypes. Thao tác IL có thể là bước xây dựng sau được kích hoạt bởi thuộc tính trên cấu trúc, ví dụ:

//Microtype representing a non-zero age, so we want to disable the default ctor 
[NoDefaultConstructor] 
public struct Age 
{ 
    public Age(int age) 
    { 
     // Implementation (including validation) elided 
    } 
} 

Trước khi điều tra thêm, tôi muốn hỏi xem có ai biết về bất kỳ sự cố nào có thể gây ra không? Tôi đã không thể nghĩ ra được.

+0

Trường hợp sử dụng của bạn cần loại tham chiếu không null là gì? –

+1

Đối với những người có ngân sách trải dài để ReSharper, có một số chức năng kiểm tra vô giá hữu ích trong đó (mặc dù rõ ràng là không hoàn thành như các công cụ hợp đồng trong các phiên bản đắt tiền của VS) – AakashM

+0

@AnthonyPegram Tôi nghĩ rằng hầu hết các tập quán tham chiếu là hoàn toàn không null , do đó, thực thi rằng thông qua chữ ký phương pháp là một chiến thắng trong điều khoản của tài liệu và an toàn. – Akash

Trả lời

6

Điều này có thể bị đánh bại khá dễ dàng - thời gian chạy không cố gắng gọi hàm tạo tham số của cấu trúc (nếu có) trong mọi trường hợp.

Cụ thể, nó sẽ không được gọi khi tạo một mảng kiểu cấu trúc.

Age[] ages = new Age[3]; 

// This guy skips your "real" ctor as well as the "invalid" parameterless one. 
Age age = ages[0]; 

... hoặc trong default(structType) biểu:

// Invalid state here too. 
Age age = default(Age); 

Từ Jon Skeet empirical research vào công cụ này, đây là một danh sách các hoạt động khác mà không gọi các nhà xây dựng:

  • Chỉ cần khai báo biến, cho dù địa phương, tĩnh hay ví dụ
  • Boxing
  • Sử dụng default(T) trong một phương pháp chung
  • Sử dụng new T() trong một phương pháp chung

Bây giờ tình hình đó để lại cho bạn trong là bạn phải bằng cách nào đó kiểm tra cho mỗi Age dụ hay không ví dụ được tạo ra bằng cách làm việc xung quanh hàng rào của bạn - không tốt hơn nhiều so với việc không dựng lên hàng rào ngay từ đầu.

+0

Cảm ơn Ani, tôi đã bỏ lỡ bài viết tiếp theo của Jon. Mặc dù đây là tất cả những mối quan tâm hợp lệ, tôi vẫn tự hỏi liệu phương pháp này có công đức hay không, đặc biệt là đối với mã nội bộ, ví dụ: NonNull trong một chữ ký phương pháp là tài liệu rõ ràng (với * một số * thực thi trình biên dịch) như các giá trị cho phép đối số. Tôi cảm thấy thoải mái với một giải pháp không hoàn hảo nếu những khiếm khuyết chỉ tiếp xúc với những người dùng độc hại (đồng nghiệp của tôi là những người chuyên nghiệp) hoặc do những tai nạn hiếm hoi. Tuy nhiên, tôi đã không quyết định liệu các ví dụ của bạn có rơi vào danh mục "tai nạn hiếm hoi" hay không! – Akash

+0

@Akash: Tôi sẽ khó phân loại một loạt các cấu trúc hoặc 'mặc định (T)' trong một phương pháp chung có khả năng là "độc hại"/một "tai nạn hiếm hoi". Khi chúng tôi chấp nhận điều đó, rõ ràng là chúng tôi sẽ phải xác thực mọi trường hợp - điều này khiến chúng tôi trở lại ngay khi bắt đầu. :) – Ani

+0

Nhưng nếu chúng ta đang giới hạn thảo luận với microtypes, tôi không thể thấy tại sao bất cứ ai sẽ khởi tạo nó thông qua một phương thức nhà máy chung (GetMicroType ). Tương tự, thay vì truyền Age [] vào một phương thức, bạn sẽ vượt qua trong một AgeCollection, mà chính nó sẽ có xác nhận hợp lệ trên ctor args của nó. Tôi đang đấu tranh để xem những gì tôi đang thiếu, nhưng với điều đó tôi không biết bất cứ ai sử dụng cách tiếp cận này, tôi cảm thấy rằng phải có những vấn đề thực tế hơn là những mối quan tâm lý thuyết đơn giản. – Akash