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?
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.
You say you want to use C#'s yield
keyword the same way you would use Ruby's yield
keyword. You seem to be a little confused about what the two actually do: the two have absolutely nothing to do with each other, what you are asking for, is simply not possible.
The C# yield
keyword is not the C# equivalent of the Ruby yield
keyword. In fact, there is no equivalent to the Ruby yield
keyword in C#. And the Ruby equivalent to C#'s yield
keyword is not the yield
keyword, it's the Enumerator::Yielder#yield
method (also aliased as Enumerator::Yielder#<<
).
IOW, it's for returning the next element of an iterator. Here's an abridged example from the official MSDN documentation:
public static IEnumerable Power(int number, int exponent) {
var counter = 0;
var result = 1;
while (counter++ < exponent) {
result *= number;
yield return result; }}
Use it like so:
foreach (int i in Power(2, 8)) { Console.Write("{0} ", i); }
The Ruby equivalent would be something like:
def power(number, exponent)
Enumerator.new do |yielder|
result = 1
1.upto(exponent-1) { yielder.yield result *= number } end end
puts power(2, 8).to_a
In C#, yield
is used to yield a value to the caller and in Ruby, yield
is used to yield control to a block argument
In fact, in Ruby, yield
is just a shortcut for Proc#call
.
Imagine, if yield
didn't exist. How would you write an if
method in Ruby? It would look like this:
class TrueClass
def if(code)
code.call
end
end
class FalseClass
def if(_); end
end
true.if(lambda { puts "It's true!" })
This is kind of cumbersome. In Ruby 1.9, we get proc literals and a shortcut syntax for Proc#call
, which make it a little bit nicer:
class TrueClass
def if(code)
code.()
end
end
true.if(->{ puts "It's true!' })
However, Yukihiro Matsumoto noticed, that the vast majority of higher-order procedures only take one procedure argument. (Especially since Ruby has several control-flow constructs built into the language, which would otherwise require multiple procedure arguments, like if-then-else
which would require two and case-when
which would require n arguments.) So, he created a specialized way to pass exactly one procedural argument: the block. (In fact, we already saw an example of this at the very beginning, because Kernel#lambda
is actually just a normal method which takes a block and returns a Proc
.)
class TrueClass
def if(&code)
code.()
end
end
true.if { puts "It's true!" }
Now, since we can only ever pass exactly one block into a method, we really don't need to explicitly name the variable, since there can never be an ambiguity anyway:
def if
???.() # But what do we put here? We don't have a name to call #call on!
end
However, since we now no longer have a name that we can send messages to, we need some other way. And again, we get one of those 80/20 solutions that are so typical for Ruby: there are tons of things that one might want to do with a block: transform it, store it in an attribute, pass it to another method, inspect it, print it … However, by far the most common thing to do is to call it. So, matz added another specialized shortcut syntax for exactly this common case: yield
means "call
the block that was passed to the method". Therefore, we don't need a name:
def if; yield end
So, what is the C# equivalent to Ruby's yield
keyword? Well, let's go back to the first Ruby example, where we explicitly passed the procedure as an argument:
def foo(bar)
bar.('StackOverflow')
end
foo ->name { puts "Higher-order Hello World from #{name}!" }
The C# equivalent is exactly the same:
void Foo(Action<string> bar) => bar("StackOverflow")
Foo(name => { Console.WriteLine("Higher-order Hello World from {0]!", name); })
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With