Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enumerable.Empty to List

Tags:

c#

If I for example have this method:

IEnumerable<int> GetRandomNumbers()
{
    // {Codes that generate numbers as List<int>}
    if(generationFails == true)
    {
        return Enumberable.Empty<int>(); // I do this to signal that we have an error
    }
    return numbers;
}

In the calling method I do:

IEnumerable<int> AddNumber(int number)
{
    var random = GetRandomNumbers();
    var randomList = random  as IList<int> ?? random.ToList(); // Run ToList only if needed
    randomList.Add(number); 
    return randomList;
}

and when generation fails I get an exception "[NotSupportedException: Collection was of a fixed size.]".

This is due to the fact that the Enumerable empty is an IList so the .ToList() is not run and I am then trying to add to a fixed Enumberable.Empty. Am I wrong in thinking that this is bad design, an object that inherits IList (where Add is defined) should support Add?

Am I forced to do var randomList = random.ToList() or stop using Enumberable.Empty? Is there some better way?

Update: I think I was unclear in my example. I wish to swallow (or log) the error but allow operation to continue without crashing. My comment "I do this to signal that we have an error" was meant to tell other developers reading the code that this is an abnormal behavior.

The answer to the question Tim linked was what I was getting at. Seems that we just don't have an interface for constant collections so IList is used.

like image 571
Martin Avatar asked Jan 08 '23 07:01

Martin


2 Answers

The better way would be returning null or throwing an exception. Returning an empty list could considered a valid alternative, but not in the context of your method (eg. filtering another list with no valid item).

A failed generation of random numbers seems to indicate a problem of the generation algorithm and should throw an exception, not an empty list.

Should a retrieval method return 'null' or throw an exception when it can't produce the return value?

If you are always expecting to find a value then throw the exception if it is missing. The exception would mean that there was a problem.

If the value can be missing or present and both are valid for the application logic then return a null.

like image 175
Sven Avatar answered Jan 11 '23 18:01

Sven


Actually Enumerable.Empty returns an empty array, that's why you get the NotSupportedException in Array.IList.Add. Arrays have a fixed size.

Why array implements IList?

I would return null instead of an empty sequence if you want to "signal that there was an error". A type check for your business logic is not good in terms of readability.

if(generationFails == true)
{
    return null; // I do this to signal that we have an error
}

Then it's easy:

IEnumerable<int> random = GetRandomNumbers();
IList<int> randomList = random == null ? new List<int>() : random.ToList();

An empty sequence suggests that everything was fine. Consider that you'll change the method in future to take an integer size. Now someone provides 0 as size which returns also an empty sequence. You can't differentiate between an error and an empty sequence anymore.

Of course you could also return new List<int> instead of Enumerable.Empty<int>.

like image 29
Tim Schmelter Avatar answered Jan 11 '23 18:01

Tim Schmelter