问题
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.ReadOnlyDictionary
2.ContainsKey(type parameter.TKey)' implements interface method 'System.Collections.Generic.IDictionary
2.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