It is now possible to specify a non-null element array. For example:
string![] msgs = new string![200];
Obviously after this statement, the array elements are null, even though the type appears to guarantee that they are non-null. Spec# prevents you from accessing elements of the array before it is fully initialized. That is done by calling a special library method:
Microsoft.Contracts.NonNullType.AssertInitialized(args);
This method inserts a run-time check that ensures every element of the array is non-null. If any of the elements are null, then an exception of type Microsoft.Contracts.NonNullType.NullException will be thrown. Calling this method is called commitment of the non-null element array. However, there is a subtle distinction between an array that is fully initialized and an array of which every element is non-null. Suppose we have objects that are not fully initialized and we use these objects in the initialization of the array elements. What is likely to happen is that after the commitment call, the array elements are still considered not fully initialized. In Spec#, such objects are called delayed objects. If you try to use a delayed object in a context that requires a non-delayed object, a warning will be generated. For example:
class Foo {
string! Name;
void bar(Foo! [] foos) {
System.Console.WriteLine(foos[0].Name); // to amplify this problem, we try to
// print foos[0].Name, which is still null
}
public Foo() {
Foo! [] foos = new Foo[1];
foos[0] = this;
Microsoft.Contracts.NonNullType.AssertInitialized(foos);
Bar(foos); // will have a warning
}
}
Possible delayed objects include: self (this) in a constructor, other non-null element arrays that have not been committed, parameters that have an explicit attribute [Delayed], or any other objects that contain a reference to a delayed object.