I have a set of children in my class, and I have an open accessor to it. I want to provide a postcondition to ensure that the elements in the collection are not null (I know that in tests 2 and 3, the caller can modify the collection, but for now, my goal is to make sure that the collection returned from the doesn property 't contain null elements).
I thought using Assume and ForAll would be enough, but that doesn't help
Here is a sample code with three classes that I tried. All three cases are absolutely identical, except that the first is ReadOnlyObservableCollection , the second is ObservableCollection , and the third is 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;
- 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;
- 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;
Here is the test code that uses these 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' }
Is there any way to define a contract so that I don't write Contract.Assume(child != null) every time I use the Children property?
Update:
I tried to implement an Enumerator that guarantees a non-empty condition in the get Current attribute, as suggested by phoog . But the warning is still present (unexpectedly 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 }
Use in code:
Test1 t1 = new Test1(); var NonNullTest1 = new NotNullEnumerable<A>(t1.Children); foreach (A child in NonNullTest1) { child.SomeMethod();
Any ideas?