2011-09-14 3 views
6

Я не уверен, если я делаю что-то здесь не так, или если оно должно быть исправлено ...Код договора: Обеспечивает недоказанной и требует НЕПОДТВЕРЖДЕННОЕ

У меня есть пользовательский словарь класс-оболочку и вот фрагмент кода, который необходим.

public int Count 
{ 
    get 
    { 
     Contract.Ensures(Contract.Result<int>() >= 0); 

     return InternalDictionary.Count; 
    } 
} 

public bool ContainsKey(TKey key) 
{ 
    //This contract was suggested by the warning message, if I remove it 
    //I still get the same warning... 
    Contract.Ensures(!Contract.Result<bool>() || Count > 0); 

    return InternalDictionary.ContainsKey(key); 
} 

Единственная причина, я добавил строку для ContainsKey, потому что я получил следующее предупреждение (и до сих пор): Codecontracts: ensures unproven: !Contract.Result<bool>() || @this.Count > 0. Я могу удалить эту строку и получить ТАКОЙ ВОПРОС!

Что мне делать, чтобы избавиться от этих проблем?


Update:

Я также попытался (как это было предложено) ...

public Boolean ContainsKey(TKey key) 
{ 
    Contract.Requires(Count == 0 || InternalDictionary.ContainsKey(key)); 
    Contract.Ensures(!Contract.Result<bool>() || Count > 0); 

    return InternalDictionary.ContainsKey(key); 
} 

Предупреждение 5 Метод «My.Collections.Generic.ReadOnlyDictionary 2.ContainsKey(type parameter.TKey)' implements interface method 'System.Collections.Generic.IDictionary 2.ContainsKey (тип parameter.TKey) ', поэтому нельзя добавить Требуется.

+0

Обратите внимание, что корень проблемы заключается в том, что этот метод обещает, что каждый ключ будет найден, и на самом деле он не имеет никакого контроля над этим. –

ответ

1

Откровенно говоря, я не понимаю пункт договора. Договор составляет

Contract.Ensures(!Contract.Result<bool>() || Count > 0); 

Что вы пытаетесь сказать? Вы не можете гарантировать, что словарь содержит ключ, а также что словарь содержит какие-либо значения вообще. Таким образом, этот контракт не всегда можно удовлетворить. Это то, что говорит вам верификатор: он не может доказать, что это утверждение, которое вы обещаете быть истинным, истинно.

Лучшее, что вы можете гарантировать, что возвращаемое значение true или возвращаемое значение false и Count больше нуля или равное нулю Но какой смысл такого договора? Вызывающий уже это знает.

Учитывая, что я вообще не стал бы обсуждать контракт.

+0

В моем вопросе я сказал, что единственная причина, по которой я добавил этот контракт, заключалась в том, что мне было сообщено предупреждение. Я получаю такое же предупреждение с или без него, и, честно говоря, я даже не понимаю, что он пытается сказать. – michael

+0

@michael: начать снова. Разве это не первый контракт? –

+0

Первоначально у меня не было контракта в коде. CodeContracts жаловался, и я поместил там контракт, потому что он заявил. Впоследствии я получаю то же предупреждение. В принципе, даже если у метода нет кода ** ЛЮБОГО ** контракта, он все равно дает такое же предупреждение. – michael

5

«У меня есть пользовательский класс-оболочка словаря», который реализует IDictionary<TKey, TValue>. Методы интерфейса могут указывать контракты, а методы класса, которые их реализуют, должны соответствовать контрактам. В этом случае IDictionary<TKey, TValue>.ContainsKey(TKey) имеет контракт вы просите о:

Contract.Ensures(!Contract.Result<bool>() || this.Count > 0); 

Логически, !a || b может быть прочитана как a ===> b (a подразумевает b), и с помощью этого мы можем перевести это на английский язык:

If ContainsKey() returns true, the dictionary must not be empty. 

Это совершенно разумное требование. Пустой словарь не должен требовать наличия ключей. Это - это то, что вам нужно доказать.

Вот пример DictionaryWrapper класса, который добавляет Contract.Ensures обещать, что деталь реализации Count равна innerDictionary.Count является твердой гарантией, что другие методы могут положиться.Он добавляет аналогичный Contract.Ensures в ContainsKey, так что договор IDictionary<TKey, TValue>.TryGetValue также поддается проверке.

public class DictionaryWrapper<TKey, TValue> : IDictionary<TKey, TValue> 
{ 
    IDictionary<TKey, TValue> innerDictionary; 

    public DictionaryWrapper(IDictionary<TKey, TValue> innerDictionary) 
    { 
     Contract.Requires<ArgumentNullException>(innerDictionary != null); 
     this.innerDictionary = innerDictionary; 
    } 

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

    public void Add(TKey key, TValue value) 
    { 
     innerDictionary.Add(key, value); 
    } 

    public bool ContainsKey(TKey key) 
    { 
     Contract.Ensures(Contract.Result<bool>() == innerDictionary.ContainsKey(key)); 
     return innerDictionary.ContainsKey(key); 
    } 

    public ICollection<TKey> Keys 
    { 
     get 
     { 
      return innerDictionary.Keys; 
     } 
    } 

    public bool Remove(TKey key) 
    { 
     return innerDictionary.Remove(key); 
    } 

    public bool TryGetValue(TKey key, out TValue value) 
    { 
     return innerDictionary.TryGetValue(key, out value); 
    } 

    public ICollection<TValue> Values 
    { 
     get 
     { 
      return innerDictionary.Values; 
     } 
    } 

    public TValue this[TKey key] 
    { 
     get 
     { 
      return innerDictionary[key]; 
     } 
     set 
     { 
      innerDictionary[key] = value; 
     } 
    } 

    public void Add(KeyValuePair<TKey, TValue> item) 
    { 
     innerDictionary.Add(item); 
    } 

    public void Clear() 
    { 
     innerDictionary.Clear(); 
    } 

    public bool Contains(KeyValuePair<TKey, TValue> item) 
    { 
     return innerDictionary.Contains(item); 
    } 

    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) 
    { 
     innerDictionary.CopyTo(array, arrayIndex); 
    } 

    public int Count 
    { 
     get 
     { 
      Contract.Ensures(Contract.Result<int>() == innerDictionary.Count); 
      return innerDictionary.Count; 
     } 
    } 

    public bool IsReadOnly 
    { 
     get 
     { 
      return innerDictionary.IsReadOnly; 
     } 
    } 

    public bool Remove(KeyValuePair<TKey, TValue> item) 
    { 
     return innerDictionary.Remove(item); 
    } 

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() 
    { 
     return innerDictionary.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return innerDictionary.GetEnumerator(); 
    } 
} 
+0

+1 для отличного логического класса. Я наткнулся на эти условные контракты раньше и забыл, что идентичность подразумевает из моих дискретных математических классов xD. – julealgon