Search code examples
c#collections

Prevent IReadOnlyCollection<T> to have default item


Is there an immutable collection that prohibits initialization with default values?

For instance:

var newObjects = new MyObject[]
        {
           default
        }

The MyObject class has a Copy method that throws an error when the parameter is set to default

public MyObject Clone()
    {
        return new MyObject(ShortName, Name);
    }

The newObjects variable iterates through the entire array and attempts to copy. However, since the only item in the array is set to default, it crashes. Is there a way to prevent this issue using a specific collection?

This is my example method:

public IEnumerable<MyObject> CopyObjects(IReadOnlyCollection<MyObject> newObjects)
    {
        var newLst = new List<MyObject>(); 
        foreach (var o in newObjects)
        {
            newLst.Add(o.Copy());
        }

        return newLst;
    }

Solution

  • Is there an immutable collection that prohibits initialization with default values?

    No, because it has nothing to do with collections but with the language itself. If MyObject is a reference type then you can leverage nullable reference types in combination with TreatWarningsAsErrors compilation option to mitigate the issue to some extent:

    var newObjects = new MyObject[]
    {
       default // warning CS8625: Cannot convert null literal to non-nullable reference type.
    };
    
    class MyObject{}
    

    Demo @sharplab.io

    Other options:

    • filtering out nulls/defaults:

      IEnumerable<MyObject> CopyObjects(IReadOnlyCollection<MyObject> newObjects) 
         => newObjects
          .Where(obj => obj is not null)
          .Select(obj => obj.Clone())
          .ToList();
      

      you can update the code to manage the default value if it is not/not only null check.

    • checking before calling Clone if the value is default one and returning default in this case. For example using Null-conditional operator ?. which will return null in case of null:

      IEnumerable<MyObject> CopyObjects(IReadOnlyCollection<MyObject> newObjects) 
         => newObjects
          .Select(obj => obj?.Clone()) 
          .ToList();
      
    • custom Roslyn analyzer