2010-07-29 23 views
11

Xem xét loại bất biến này:Hợp đồng mã: Tại sao một số bất biến không được xem xét bên ngoài lớp học?

public class Settings 
{ 
    public string Path { get; private set; } 

    [ContractInvariantMethod] 
    private void ObjectInvariants() 
    { 
     Contract.Invariant(Path != null); 
    } 

    public Settings(string path) 
    { 
     Contract.Requires(path != null); 
     Path = path; 
    } 
} 

Hai điều cần chú ý ở đây:

  • Có một hợp đồng bất biến mà đảm bảo Path sở hữu có thể không bao giờ có null
  • Các nhà xây dựng sẽ kiểm tra giá trị path luận để tôn trọng bất hợp đồng trước đó

Tại thời điểm này, một cá thể Setting không bao giờ có thể là thuộc tính nullPath.

Bây giờ, nhìn vào kiểu này:

public class Program 
{ 
    private readonly string _path; 

    [ContractInvariantMethod] 
    private void ObjectInvariants() 
    { 
     Contract.Invariant(_path != null); 
    } 

    public Program(Settings settings) 
    { 
     Contract.Requires(settings != null); 
     _path = settings.Path; 
    } // <------ "CodeContracts: invariant unproven: _path != null" 
} 

Về cơ bản, nó có hợp đồng riêng của mình bất biến (trên _path trường) mà không thể được thỏa mãn trong việc kiểm tra tĩnh (x bình luận ở trên). Đó có vẻ hơi lạ với tôi, vì nó dễ dàng để chứng minh điều đó:

  • settings là bất biến
  • settings.Path không thể được null (vì Cài đặt có hợp đồng tương ứng bất biến)
  • nên bằng cách gán settings.Path để _path, _path không được rỗng

Tôi có bỏ sót điều gì ở đây không?

Trả lời

10

Sau khi kiểm tra các code contracts forum, tôi thấy this similar question với câu trả lời sau đây từ một trong những nhà phát triển:

Tôi nghĩ rằng hành vi mà bạn đang trải qua là do một số suy luận liên phương pháp đó đang xảy ra. Trình kiểm tra tĩnh đầu tiên phân tích các hàm tạo, sau đó các thuộc tính và sau đó là các phương thức. Khi phân tích hàm tạo của Sample, nó không biết rằng msgContainer.Something! = Null để nó phát ra cảnh báo. Một cách để giải quyết nó, hoặc là bằng cách thêm một msgumption msgContainer.Something! = Null trong constuctor, hoặc tốt hơn để thêm postcondition! = Null to Something.

Vì vậy, nói cách khác, lựa chọn của bạn là:

  1. Tận dụng tối Settings.Path sở hữu rõ ràng thay vì tự động, và chỉ định bất biến trên các lĩnh vực ủng hộ để thay thế. Để đáp ứng bất biến của bạn, bạn sẽ cần thêm điều kiện tiên quyết vào bộ truy cập đã đặt của thuộc tính: Contract.Requires(value != null).

    Bạn có thể tùy ý thêm điều kiện vào bộ truy cập nhận được với Contract.Ensures(Contract.Result<string>() != null), nhưng trình kiểm tra tĩnh sẽ không phàn nàn theo cách nào.

  2. Thêm Contract.Assume(settings.Path != null) vào hàm tạo của lớp Program.

0

Biến thể không hoạt động trên các thành viên riêng tư, bạn thực sự không thể có lý do tại sao theo cách này, hy vọng điều này sẽ hữu ích.

+0

Có, họ thực hiện. Nếu không thì bất biến sẽ giúp ích rất ít. –

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