I have a collection of child items in my class and I have a public accessor to it. I want to provide a postcondition to ensure that items in the collection are not null (I know, that in tests 2 and 3 caller can change the collection, but for now my goal is just to make sure, that collection returned from the property doesn't contain null items).
I thought using Assume and ForAll would be enough, but that doesn't help
Here is the sample code with 3 classes that I tried. All 3 cases are allmost identical except that first exposes ReadOnlyObservableCollection, 2nd - ObservableCollection, and 3rd - List.
- ReadOnlyObservableCollection
class Test1
{
public Test1()
{
_children = new ObservableCollection<A>();
_childrenReadOnly = new ReadOnlyObservableCollection<A>(_children);
}
protected readonly ObservableCollection<A> _children;
protected readonly ReadOnlyObservableCollection<A> _childrenReadOnly;
public ReadOnlyObservableCollection<A> Children
{
get
{
Contract.Ensures(Contract.ForAll(Contract.Result<ReadOnlyObservableCollection<A>>(), i => i != null));
Contract.Assume(Contract.ForAll(_childrenReadOnly, i => i != null));
return _childrenReadOnly; // CodeContracts: ensures unproven: Contract.ForAll(Contract.Result<ReadOnlyObservableCollection<A>>(), i => i != null)
}
}
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(_children != null);
Contract.Invariant(_childrenReadOnly != null);
}
}
- ObservableCollection
class Test2
{
public Test2()
{
_children = new ObservableCollection<A>();
}
protected readonly ObservableCollection<A> _children;
public ObservableCollection<A> Children
{
get
{
Contract.Ensures(Contract.ForAll(Contract.Result<ObservableCollection<A>>(), i => i != null));
Contract.Assume(Contract.ForAll(_children, i => i != null));
return _children; // CodeContracts: ensures unproven: Contract.ForAll(Contract.Result<ObservableCollection<A>>(), i => i != null)
}
}
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(_children != null);
}
}
- List
class Test3
{
protected readonly List<A> _children = new List<A>();
public List<A> Children
{
get
{
Contract.Ensures(Contract.ForAll(Contract.Result<List<A>>(), i => i != null));
Contract.Assume(Contract.ForAll(_children, i => i != null));
return _children; // No warning here when using List instead of ObservableCollection
}
}
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(_children != null);
}
}
Here is the test code that uses this classes:
Test1 t1 = new Test1();
foreach (A child in t1.Children)
{
child.SomeMethod(); // CodeContracts: Possibly calling a method on a null reference 'child'
}
Test2 t2 = new Test2();
foreach (A child in t2.Children)
{
child.SomeMethod(); // CodeContracts: Possibly calling a method on a null reference 'child'
}
Test3 t3 = new Test3();
foreach (A child in t3.Children)
{
child.SomeMethod(); // CodeContracts: Possibly calling a method on a null reference 'child'
}
Can I somehow define a contract, in order not to write Contract.Assume(child != null)
every time I use Children
property?
Update:
I tried to implement Enumerator
that ensures not null condition in Current
property getter, as was suggested by phoog. But the warning is still present (surprisingly for me).
public class NotNullEnumerable<T> : IEnumerable<T>
{
private IEnumerable<T> _enumerable;
public NotNullEnumerable(IEnumerable<T> enumerable)
{
_enumerable = enumerable;
}
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
return new NotNullEnumerator<T>(_enumerable.GetEnumerator());
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
public class NotNullEnumerator<T> : IEnumerator<T>
{
private readonly IEnumerator<T> _enumerator;
public NotNullEnumerator(IEnumerator<T> enumerator)
{
_enumerator = enumerator;
}
#region IEnumerator<T> Members
public T Current
{
get
{
Contract.Ensures(Contract.Result<T>() != null);
return _enumerator.Current;
}
}
#endregion
#region IDisposable Members
public void Dispose()
{
_enumerator.Dispose();
}
#endregion
#region IEnumerator Members
object System.Collections.IEnumerator.Current
{
get
{
Contract.Ensures(Contract.Result<object>() != null);
return _enumerator.Current;
}
}
public bool MoveNext()
{
return _enumerator.MoveNext();
}
public void Reset()
{
_enumerator.Reset();
}
#endregion
}
Usage in code:
Test1 t1 = new Test1();
var NonNullTest1 = new NotNullEnumerable<A>(t1.Children);
foreach (A child in NonNullTest1)
{
child.SomeMethod(); // CodeContracts: Possibly calling a method on a null reference 'child'
}
Any ideas?