Search code examples
c#nullability

How to implement method accepting ICollection<T> and ICollection<T?>


Given the following method:

public static void DisposeItems<T>(this ICollection<T?> collection)
    where T : class, IDisposable
{
    foreach (var item in collection)
    {
        item?.Dispose();
    }

    if (!collection.IsReadOnly)
    {
        collection.Clear();
    }
}

This is called in something like:

private static void CleanupNullable(List<TestClass?> collection)
{
    collection.DisposeItems();
}

private static void Cleanup(List<TestClass> collection)
{
    collection.DisposeItems();
}

The second gives the error: collection cannot be used to due difference of nullability in the reference types.

A similar implementation accepting IEnumerable<T?> works fine because IEnumerable is co-variant.

I cannot create an additional method accepting ICollection<T> because nullability is not part of the signature. Is there any way I can compile this as it worked pre-nullability?

Dropping the class constraint or changing it to class? gives errors when calling it with Collection<TestClass?> because TestClass? doesn't match constraint IDisposable.


Solution

  • This is because you've put the question mark in the wrong place. If your generic constraint doesn't care if a type is nullable, you add the question mark to the type in the where expression, rather than the argument list. Plus you need to add that "don't care" question mark to all of the constraints for that type.

    public static void DisposeItems<T>(this ICollection<T> collection)
        where T : class?, IDisposable?