Search code examples
c#ienumerableyield-return

Multi-yield mechanism in C#


I have a question over on Code Review SE where I'm struggling to work out how to refactor my enumerator method to be less of a complete mess.

I think part of the problem is I can't work out how to call other methods from inside it and have them yield results without having to wrap that inner call inside a foreach and yeild out the items one by one.

Is there any way to do some sort of multi-yield in C# so that this would work?

    private IEnumerable<int> Outer()
    {
        yield return 0;
        yield return Inner(); // Some sort of multi-yield
        yield return 5;
    }
    
    private IEnumerable<int> Inner()
    {
        yield return 1;
        yield return 2;
        yield return 3;
        yield return 4;
    }

I know I can do this, but this isn't what I'm looking for as by the time I've done this a few times, my refactored version wouldn't be much better:

    private IEnumerable<int> Outer()
    {
        yield return 0;
        foreach (int i in Inner())
        {
            yield return i;
        }
        yield return 5;
    }

Note: I've since decided that the answer to my refactoring question was that I don't need an Enumerable in that case. However, this question is still valid in-case if I wanted to expose something like that as an enumerable from a library or something. It just isn't the best option for the linked problem. I'll leave it linked for extra context though.


Solution

  • You can not do better if you keep some yield return statements at the top level method. But if all yield return statements are at the leaf methods, you can use IEnumerable.Concat:

        private IEnumerable<int> Outer()
        {
            return Inner1().Concat(Inner2()).Concat(Inner3());
        }
    
        private IEnumerable<int> Inner1()
        {
            yield return 0;
        }
        
        private IEnumerable<int> Inner2()
        {
            yield return 1;
            yield return 2;
            yield return 3;
            yield return 4;
        }
    
        private IEnumerable<int> Inner3()
        {
            yield return 5;
        }