Search code examples
c#closuresdryyield

using yield in C# like I would in Ruby


Besides just using yield for iterators in Ruby, I also use it to pass control briefly back to the caller before resuming control in the called method. What I want to do in C# is similar. In a test class, I want to get a connection instance, create another variable instance that uses that connection, then pass the variable to the calling method so it can be fiddled with. I then want control to return to the called method so that the connection can be disposed. I guess I'm wanting a block/closure like in Ruby. Here's the general idea:

private static MyThing getThing()
{
    using (var connection = new Connection())
    {
        yield return new MyThing(connection);
    }
}

[TestMethod]
public void MyTest1()
{
    // call getThing(), use yielded MyThing, control returns to getThing()
    // for disposal
}

[TestMethod]
public void MyTest2()
{
    // call getThing(), use yielded MyThing, control returns to getThing()
    // for disposal
}

...

This doesn't work in C#; ReSharper tells me that the body of getThing cannot be an iterator block because MyThing is not an iterator interface type. That's definitely true, but I don't want to iterate through some list. I'm guessing I shouldn't use yield if I'm not working with iterators. Any idea how I can achieve this block/closure thing in C# so I don't have to wrap my code in MyTest1, MyTest2, ... with the code in getThing()'s body?


Solution

  • What you want are lambda expressions, something like:

    // not named GetThing because it doesn't return anything
    private static void Thing(Action<MyThing> thing)
    {
        using (var connection = new Connection())
        {
            thing(new MyThing(connection));
        }
    }
    
    // ...
    // you call it like this
    Thing(t=>{
      t.Read();
      t.Sing();
      t.Laugh();
    });
    

    This captures t the same way yield does in Ruby. The C# yield is different, it constructs generators that can be iterated over.