Search code examples
c#linqextension-methods

Should I use Yield when writing my own extension?


I wanted to write an extension method (for using it in a fluent syntax) so that If a sequence is :

List< int> lst  = new List< int>(){1,2,3 };

I want to repeat it 3 times (for example). so the output would be 123123123

I wrote this :

 public static  IEnumerable<TSource>  MyRepeat<TSource>(this IEnumerable<TSource>  source,int n)
    {
         return    Enumerable.Repeat(source,n).SelectMany(f=>f);
    }

And now I can do this :

  lst.MyRepeat(3)

output :

enter image description here

Question :

Shouldn't I use Yield in the extension method ? I tried yield return but it's not working here. Why is that and should I use it.

edit

After Ant's answer I changed it to :

public static  IEnumerable<TSource>  MyRepeat<TSource>(this IEnumerable<TSource>  source,int n)
    {
        var k=Enumerable.Repeat(source,n).SelectMany(f=>f);
        
                foreach (var element in k)
                {
                    yield   return    element;
                }
    }

But is there any difference ?


Solution

  • This is because the following already returns an IEnumerable:

    Enumerable.Repeat(source,n).SelectMany(f=>f);
    

    When you use the yield keyword, you specify that a given iteration over the method will return what follows. So you are essentially saying "each iteration will yield an IEnumerable<TSource>," when actually, each iteration over a method returning an IEnumerable<TSource>should yield a TSource.

    Hence, your error - when you iterate over MyRepeat, you are expected to return a TSource but because you are trying to yield an IEnumerable, you are actually trying to return an IEnumerable from every iteration instead of returning a single element.

    Your edit should work but is a little pointless - if you simply return the IEnumerable directly it won't be enumerated until you iterate over it (or call ToList or something). In your very first example, SelectMany (or one of its nested methods) will already be using yield, meaning the yield is already there, it's just implicit in your method.