简体   繁体   中英

Enumerable.Empty to List

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.

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.

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> .

Another possible way to tackle this would be to return an empty enumerator using yield break :

IEnumerable<int> GetRandomNumbers()
{
    if (generationFails)
        yield break;

    foreach (var element in numbers)
    {
        yield return element;
    }
}

This will make your IEnumerable<int> lazily return each of the random numbers.

Note this will not single an error to the calling code. If generationFails should single an error in code execution, you should definitely throw an exception, as others have stated.

With Enumerable.Empty() method you use cached array instead of creating a new one. It can be positively affect performance because your code will less often bother Garbage Collector.

Have a look to Enumerable.Empty() vs new 'IEnumerable'() – what's better?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM