0

I was wondering when yield would be useful. It seems to me that I can use Linq everytime I can use yield.

Let's say I have this Test class

public class Test
{
    public object Test1;
    public object Test2;

    public Test(object test1, object test2)
    {
        this.Test1 = test1;
        this.Test2 = test2;
    }
}

And those two DataTables

DataTable dt1 = new DataTable();
dt1.Columns.Add("test1", typeof(string));
dt1.Columns.Add("test2", typeof(string));
dt1.Rows.Add("a1", "a2");
dt1.Rows.Add("b1", "b2");

DataTable dt2 = new DataTable();
dt2.Columns.Add("test1", typeof(string));
dt2.Columns.Add("test2", typeof(string));
dt2.Rows.Add("c1", "c2");
dt2.Rows.Add("d1", "d2");

Example 1

If I want to get a IEnumerable<Test> for dt1 I could do

IEnumerable<Test> GetTests(DataTable dt)
{
    foreach (DataRow row in dt.Rows)
    {
        yield return new Test(row["test1"], row["test2"]);
    }
}

IEnumerable<Test> tests = GetTests(dt1);

But I could simply do

IEnumerable<Test> testsLinq = dt1.Rows.OfType<DataRow>()
                                      .Select(row => new Test(row["test1"], row["test2"]));

Example 2

Another yield use I know is to merge

IEnumerable<Test> MergeTests(DataTable dt1, DataTable dt2)
{
    foreach (DataRow row in dt1.Rows)
    {
        yield return new Test(row["test1"], row["test2"]);
    }

    foreach (DataRow row in dt2.Rows)
    {
        yield return new Test(row["test1"], row["test2"]);
    }
}

IEnumerable<Test> mergedTests = MergeTests(dt1, dt2);

But again, I could do

IEnumerable<Test> mergedTestsLinq = dt1.Rows.OfType<DataRow>()
                                            .Select(row => new Test(row["test1"], row["test2"]))
                                            .Union(dt2.Rows.OfType<DataRow>()
                                                           .Select(row => new Test(row["test1"], row["test2"])));

Is there some case I am not aware of where yield is best used over Linq?

Arthur Rey
  • 2,990
  • 3
  • 19
  • 42

1 Answers1

1

yield return is a lot more flexible when the data structure is not linear.

For example, you could use it to enumerate a tree in preorder, postorder, or inorder:

IEnumerable<T> InorderTree<T>(TreeNode<T> node) {
    if (node.Left != null) {
        foreach (var x in InorderTree(node.Left)) {
            yield return x;
        }
    }
    if (node.Right != null) {
        foreach (var x in InorderTree(node.Right)) {
            yield return x;
        }
    }
    yield return node.Value;
}

You could also produce a method that yields a sequence of Fibonacci numbers:

IEnumerable<int> Fibonacci(int n) {
    int first = 0, second = 1;
    for (int c = 0 ; c < n ; c++ ) {
        int next;
        if ( c <= 1 ) {
            next = c;
        } else {
            next = first + second;
            first = second;
            second = next;
        }
        yield return next;
    }
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523