开发者

Yield Return with Null

Is there any way to optionally return a null with a "return yield" driven iterator?

I would like to return a null in some cases and I don't think this is particular to IEnumerable of type开发者_StackOverflow string. Same goes for IEnumerable of type int etc. Thanks

static void Main(string[] args)
{
    var Items = GetItems();

    if (Items != null)
    {
        foreach (var item in Items)
        {
            Console.WriteLine(item);
        }
    }
    else
    {
        Console.WriteLine("<null>");
    }
}

static IEnumerable<string> GetItems()
{
    if (false)
    {
        yield return "Andy";
        yield return "Jennifer";
    }

    return null; // <- Compiler Error:
    // Cannot return a value from an iterator. 
    // Use the yield return statement to return a value,
    // or yield break to end the iteration.
}


If you need to things like that (or throw things like ArgumentException immediately), you need to separate your iterator into two methods:

 public IEnumerable<string> GetItems() {
     if (something) return null;
     return GetItemsInternal();
 }

 private IEnumerable<string> GetItemsInternal() {
     // the actual iterator with "yield return" goes here.
 }


You're not using an enumerable as it was intended (to iterate objects in a collection). If you want to keep your code similar to what it is now, you should do something like this:

static void Main(string[] args)
{
    var Items = GetItems();

    foreach (var item in Items) //this will not enter the loop because there are no items in the Items collection
    {
            Console.WriteLine(item);
    }

    //if you still need to know if there were items, check the Count() extension method
    if(Items.Count() == 0)
    {
      Console.WriteLine("0 items returned");
    }


}

static IEnumerable<string> GetItems()
{
    if (false)
    {
        yield return "Andy";
        yield return "Jennifer";
    }

    yield break;
}


This just isn't encouraged. When you're talking about a sequence, "null" should generally have the same semantics as "empty list."

Also, it's impossible to design the language to work in the way you'd like it to work here without extra syntax, since what if you were to hit a "yield return [whatever]" and then a "return null?"


While yield break is propably the best answer and it really does not matter since you always can do Items.Count() to check if greater zero or even do for each on your empty result there could be situations where it does matter if your result is an empty list or nothing at all and you still want to utilize the power of yield.

In that case this will help.

    private IEnumerable<T> YieldItems<T>(IEnumerable<T> items, Action empty = null)
    {
        if (items == null)
        {
            if (empty != null) empty();
            yield break;
        }

        foreach (var item in items)
        {
            yield return item;
        }
    }

Usage

        foreach (var item in YieldItems<string>(null, () =>
        {
            Console.WriteLine("Empty");
        }))
        {
            Console.WriteLine(item);
        }


There is no way to return a null IEnumerable<T> from within an iterator method. You can return null values in the iterator but not a null IEnumerable<T>

What you could do though is have a wrapper method which either returns null or calls to the real iterator

static IEnumerable<string> GetItems() {
    if (false) {
        return GetItemsCore();
    }
    return null;
}

static IEnumerable<string> GetItemsCore() {
    yield return "Andy";
    yield return "Jennifer";
}


There is nothing that prevents you from doing a yield return null;, if it is appropriate (of course, the enumerated type must be nullable).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜