2015-05-29 22 views
13

Có rất nhiều thông tin kiểm tra tĩnh của Contract.ForAll chỉ giới hạn hoặc không có hỗ trợ.Hợp đồng mã - ForAll - Những gì được hỗ trợ bởi xác minh tĩnh

tôi đã làm rất nhiều thử nghiệm và thấy nó có thể làm việc với:

  • Contract.ForAll(items, i => i != null)
  • Contract.ForAll(items, p) nơi p là loại Predicate<T>

không thể làm việc với:

  • truy cập Dòng
  • truy cập tài sản
  • nhóm
  • Method (Tôi nghĩ đại biểu được phân bổ ở đây anyway)
  • Instance gọi phương thức

Câu hỏi của tôi là:

  • là gì các loại mã khác mà ForAll có thể hoạt động với?
  • Hợp đồng mã có đảm bảo rằng sau khi Contract.ForAll(items, i => i != null) được chứng minh, rằng khi lấy một mục từ danh sách sau này trong mã (tức là bằng cách lập chỉ mục), mục đó không phải là rỗng?

Ở đây có đầy đủ mã kiểm tra:

public sealed class Test 
{ 
    public bool Field; 
    public static Predicate<Test> Predicate; 

    [Pure] 
    public bool Property 
    { 
     get { return Field; } 
    }  

    [Pure] 
    public static bool Method(Test t) 
    { 
     return t.Field; 
    } 

    [Pure] 
    public bool InstanceMethod() 
    { 
     return Field; 
    } 

    public static void Test1() 
    { 
     var items = new List<Test>(); 
     Contract.Assume(Contract.ForAll(items, i => i != null)); 
     Contract.Assert(Contract.ForAll(items, i => i != null)); // OK 
    } 

    public static void Test2() 
    { 
     var items = new List<Test>(); 
     Contract.Assume(Contract.ForAll(items, Predicate)); 
     Contract.Assert(Contract.ForAll(items, Predicate)); // OK 
    } 

    public static void Test3() 
    { 
     var items = new List<Test>(); 
     Contract.Assume(Contract.ForAll(items, i => i.Field)); 
     Contract.Assert(Contract.ForAll(items, i => i.Field)); // assert unproven 
    } 

    public static void Test4() 
    { 
     var items = new List<Test>(); 
     Contract.Assume(Contract.ForAll(items, i => i.Property)); 
     Contract.Assert(Contract.ForAll(items, i => i.Property)); // assert unproven 
    } 

    public static void Test5() 
    { 
     var items = new List<Test>(); 
     Contract.Assume(Contract.ForAll(items, Method)); 
     Contract.Assert(Contract.ForAll(items, Method)); // assert unproven 
    } 

    public static void Test6() 
    { 
     var items = new List<Test>(); 
     Contract.Assume(Contract.ForAll(items, i => i.InstanceMethod())); 
     Contract.Assert(Contract.ForAll(items, i => i.InstanceMethod()));// assert unproven 
    } 
} 

Trả lời

1

By dịch ngược mscorelib.dll System.Diagnostics.Contracts chúng ta có thể xem như thế nào easely Contract.ForAll được xây dựng: Phải mất việc thu thập và vị ngữ.

public static bool ForAll<T>(IEnumerable<T> collection, Predicate<T> predicate) 
{ 
    if (collection == null) 
    { 
     throw new ArgumentNullException("collection"); 
    } 
    if (predicate == null) 
    { 
     throw new ArgumentNullException("predicate"); 
    } 
    foreach (T current in collection) 
    { 
     if (!predicate(current)) 
     { 
      return false; 
     } 
    } 
    return true; 
} 

Vì vậy, khi bạn nói Contract.ForAll(items, i => i.Field) trong trường hợp này i => i.Field là vị

Sau đó, bằng cách làm theo ví dụ của bạn trong tất cả các phương pháp kiểm tra, chúng ta có thể thấy rằng bạn cung cấp một danh sách trống để Contract.ForAll phương pháp đó sẽ trở thành sự thật như nó sẽ không bao giờ nhập khối foreach.

Lấy nó hơn nữa, nếu bạn thêm mục vào danh sách của bạn var items = new List<Test>() {new Test()}; và chạy thử nghiệm một lần nữa nó sẽ trả về false như public bool Field; của bạn là sai theo mặc định

Mục tiêu của Contract.ForAll là

Xác định xem tất cả các phần tử trong bộ sưu tập có tồn tại trong một hàm

Vì vậy, kết luận của tôi là không phải về C ontarct.ForAll không thể làm việc với thứ gì đó, ít nhất một phần tử trong bộ sưu tập của bạn trả về false hoặc là null

+2

Cảm ơn bạn đã nỗ lực, nhưng câu hỏi của tôi là về khả năng phân tích tĩnh được thực hiện bởi Công cụ hợp đồng mã. Nó không phải là ở tất cả về đặc tính thời gian chạy như được thực hiện trong mã của chức năng ForAll. –

4

Tôi không thể tìm thấy các biểu thức hoạt động nhiều hơn, trên thực tế tôi thấy rằng thậm chí Contract.ForAll(items, i => i != null) không hoạt động đáng tin cậy (nhưng nó hiểu rằng các mục không phải là null khi sau này được sử dụng bên trong foreach trong cùng một chức năng). Cuối cùng, tôi đã từ bỏ khả năng sử dụng các hợp đồng ForAll phức tạp hơn với trình kiểm tra tĩnh.

Thay vào đó, tôi đã nghĩ ra một cách để kiểm soát hợp đồng nào là dành cho trình kiểm tra tĩnh và dành cho trình kiểm tra thời gian chạy. Tôi trình bày phương pháp này ở đây, với hy vọng rằng nó có thể hữu ích cho những người thú vị trong câu hỏi ban đầu. Lợi ích là khả năng viết các hợp đồng phức tạp hơn, chỉ có thể được kiểm tra trong thời gian chạy và chỉ để lại các hợp đồng dễ kiểm chứng đối với kiểm tra tĩnh (và dễ dàng giữ cảnh báo ở mức thấp).

Cho rằng, 2 xây dựng gỡ lỗi là cần thiết (Nếu bạn chưa có), gỡ lỗigỡ lỗi + tĩnh Hợp đồng, The gỡ lỗi xây dựng có biểu tượng biên soạn có điều kiện MYPROJECT_CONTRACTS_RUNTIME xác định. Bằng cách này, nó nhận được tất cả các hợp đồng Contract.RtContract.. Các bản dựng khác chỉ nhận được Contract. hợp đồng.

public static class RtContract 
{ 
    [Pure] [ContractAbbreviator] [Conditional("MYPROJECT_CONTRACTS_RUNTIME")] 
    public static void Requires(bool condition) 
    { 
     Contract.Requires(condition); 
    } 

    [Pure] [ContractAbbreviator] [Conditional("MYPROJECT_CONTRACTS_RUNTIME")] 
    public static void Ensures(bool condition) 
    { 
     Contract.Ensures(condition); 
    } 

    [Pure] [Conditional("MYPROJECT_CONTRACTS_RUNTIME")] 
    public static void Assume(bool condition) 
    { 
     Contract.Assume(condition); 
    } 
} 

public class Usage 
{ 
    void Test (int x) 
    { 
     Contract.Requires(x >= 0); // for static and runtime 
     RtContract.Requires(x.IsFibonacci()); // for runtime only 
    } 
} 
Các vấn đề liên quan