Nullable types and Interfaces

There has been some discussion(https://lab.msdn.microsoft.com/ProductFeedback/viewFeedback.aspx?feedbackid=cdaf30a6-a601-43d7-8565-7096f82851ba) on whether T?, aka Nullable<T>, should implement the same interfaces as the underlying type T. At first glance, this seems reasonable enough – a T? is a little more than a T, so having T? implement the same interfaces as T should just fall right out.

 

Unfortunately, it is not that simple. Let’s consider this example to illustrate where the problems lie:

 

interface IElement<T>

{

    T Copy();

    bool IsEqual(T t);

}

class Collection<T>

    where T : IElement<T>

{

    public Collection<T> DeepCopy() {

        Collection<T> newCollection = new Collection<T>();

        foreach (T element in this)

            newCollection.Add(element.Copy());

    }

   

    public bool CompareElements(int indexA, int indexB) {

        return this[indexA].IsEqual(this[indexB]);

    }

    public T this[int index]

    {

        get { return elements[index]; }

    }

    public void Add(T newElement) { }

    T[] elements;

}

   

struct Element : IElement<Element>

{

    public Element Copy() { ... }

    public bool IsEqual(Element other) { ... }

}

 

The constraint where T : IElement<T> allows the DeepCopy and CompareElements methods to use the Copy and IsEqual methods on the elements in the collection. The Element struct implements IElement<Element> which satisfies the constraint, allowing it to be used with our container type as Collection<Element>.

Now if Element? implemented the same interfaces as Element, it should also be able to be used wherever Element is used, and we should be able to create a Collection<Element?>. Right? Not so fast. For Element? to satisfy the constraint where where T : IElement<T>, it must implement IElement<Element?>  not IElement<Element>.  You can see why this is by looking at this line in DeepCopy():

 

            newCollection.Add(element.Copy());

 

The Copy() method must return the element type of the collection for this to type check.

 

I hope this helps.