Code Contracts: Ensures Unproven & Requires Unproven

痴心易碎 提交于 2021-02-07 13:19:48

问题


I'm not sure if I'm doing something wrong here or if it needs to be fixed...

I have a custom Dictionary wrapper class and here is a snippet of the code that is necessary.

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);
}

The only reason I added the line for the ContainsKey is because I got the following warning message (and still do): Codecontracts: ensures unproven: !Contract.Result<bool>() || @this.Count > 0. I can remove this line and still get the SAME ISSUE!

What do I do here to get rid of these issues?


Update:

I also tried (as suggested)...

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

    return InternalDictionary.ContainsKey(key);
}

Warning 5 Method 'My.Collections.Generic.ReadOnlyDictionary2.ContainsKey(type parameter.TKey)' implements interface method 'System.Collections.Generic.IDictionary2.ContainsKey(type parameter.TKey)', thus cannot add Requires.


回答1:


"I have a custom Dictionary wrapper class" - that implements IDictionary<TKey, TValue>. Interface methods can specify contracts, and the class methods that implement them must meet the contracts. In this case, IDictionary<TKey, TValue>.ContainsKey(TKey) has the contract you're asking about:

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

Logically, !a || b can be read as a ===> b (a implies b), and using that, we can translate this to English:

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

This is a perfectly sensible requirement. An empty dictionary must not claim to contain keys. This is what you need to prove.

Here's a sample DictionaryWrapper class that adds Contract.Ensures to promise that the implementation detail of Count being equal to innerDictionary.Count is a hard guarantee that other methods can rely upon. It adds a similar Contract.Ensures to ContainsKey so that the IDictionary<TKey, TValue>.TryGetValue contract is also verifiable.

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();
    }
}



回答2:


Frankly I don't understand the point of the contract. The contract is

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

What are you trying to say? You can neither guarantee that the dictionary contains the key, nor that the dictionary contains any values at all. So this contract can't always be met. That's what the verifier is telling you: it can't prove that this statement you are promising to be true is true.

The best you can ensure that the return value is true or the return value is false and that Count is greater than zero or equal to zero But what's the point of such a contract? The caller already knows this.

Given that, I wouldn't bother with a contract here at all.



来源:https://stackoverflow.com/questions/7419134/code-contracts-ensures-unproven-requires-unproven

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!