использование yield в C#, как и в Ruby
кроме того, только с помощью yield
для итераторов в Ruby я также использую его для краткой передачи управления вызывающему объекту перед возобновлением управления в вызываемом методе. Что я хочу сделать в C# похож. В тестовом классе я хочу получить экземпляр соединения, создать другой экземпляр переменной, который использует это соединение, а затем передать переменную вызывающему методу, чтобы с ней можно было возиться. Затем я хочу, чтобы элемент управления вернулся к вызываемому методу, чтобы соединение можно было удалить. Наверное, я ... желая блок / закрытие, как в Ruby. Вот общая идея:
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
}
...
это не работает в C#; ReSharper говорит мне, что тело getThing
не может быть блоком итератора, потому что MyThing
не является типом интерфейса итератора. Это определенно так, но я не хочу повторять какой-то список. Я предполагаю, что я не должен использовать yield
если я не работаю с итераторами. Любая идея, как я могу достичь этого блока / закрытия в C#, поэтому мне не нужно обертывать свой код в MyTest1
, MyTest2
, ... с кодом getThing()
тело?
5 ответов
то, что вы хотите, это лямбда-выражения, что-то вроде:
// 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();
});
это захватывает t
таким же образом yield
в Руби. C# yield
отличается, он создает генераторы,которые можно перебирать.
вы говорите, что хотите использовать C# ' S В C# IOW, это для возврата следующего элемента итератора. Вот сокращенный пример из официальной документации MSDN: используйте его так: эквивалент Ruby будет чем-то вроде: В C# на самом деле, в Ruby, представьте себе, если это довольно громоздко. В Ruby 1.9 мы получаем литералы proc и ярлык синтаксис однако, Юкихиро Мацумото заметил, что тот vast большинство процедур более высокого порядка принимают только один процедура аргумент. (Тем более, что Ruby имеет несколько построений потока управления, встроенных в язык, которые в противном случае потребовали бы нескольких аргументов процедуры, таких как теперь, поскольку мы можем передать только один блок в метод, нам действительно не нужно явно называть переменную, так как в любом случае не может быть двусмысленности: однако, так как мы сейчас нет дольше есть имя, на которое мы можем отправлять сообщения, нам нужен какой-то другой способ. И снова мы получаем одно из тех 80/20 решений, которые так типичны для Ruby: there are Т вещей, которые можно было бы сделать с блоком: преобразовать его, сохранить его в атрибуте, передать его другому методу, проверить его, распечатать его ... однако далеко самое распространенное, что нужно сделать, это назвать его. Таким образом, matz добавил еще один специализированный синтаксис ярлыка именно для этого общего случая: так что is эквивалент C# для Ruby's эквивалент C# -ровно так же:yield
ключевое слово так же, как вы бы использовать Руби yield
ключевое слово. Вы, кажется, немного смущены тем, что они на самом деле делают: у них есть абсолютно ничего
yield
ключевое слово не C# эквивалент Рубина yield
ключевое слово. На самом деле, там нет эквивалент Рубина yield
ключевое слово в С.# И Рубин, эквивалентный C# ' S yield
ключевое слово не the yield
ключевое слово, это Enumerator::Yielder#yield
метод (также псевдоним Enumerator::Yielder#<<
).public static IEnumerable Power(int number, int exponent) {
var counter = 0;
var result = 1;
while (counter++ < exponent) {
result *= number;
yield return result; }}
foreach (int i in Power(2, 8)) { Console.Write("{0} ", i); }
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
yield
используется для получения стоимостью до абонента и в Ruby, yield
используется для выход управления до заблокировать аргументyield
- это просто ярлык для Proc#call
.yield
не существует. Как бы вы написали if
метод в Ruby? Это будет выглядеть так:class TrueClass
def if(code)
code.call
end
end
class FalseClass
def if(_); end
end
true.if(lambda { puts "It's true!" })
Proc#call
, что делает его немного приятнее:class TrueClass
def if(code)
code.()
end
end
true.if(->{ puts "It's true!' })
if-then-else
что потребует двух, а case-when
что потребует N аргументов.) Итак, он создал специализированный способ пройти ровно процедурный аргумент: блок. (На самом деле, мы уже видели пример этого в самом начале, потому что Kernel#lambda
на самом деле это обычный метод, который принимает блок и возвращает Proc
.)class TrueClass
def if(&code)
code.()
end
end
true.if { puts "It's true!" }
def if
???.() # But what do we put here? We don't have a name to call #call on!
end
yield
означает "call
блок, который был передан в метод". Поэтому нам не нужно имя:def if; yield end
yield
ключевое слово? Ну, давайте вернемся к первому примеру Ruby, где мы явно передали процедуру в качестве аргумента:def foo(bar)
bar.('StackOverflow')
end
foo ->name { puts "Higher-order Hello World from #{name}!" }
void Foo(Action<string> bar) => bar("StackOverflow")
Foo(name => { Console.WriteLine("Higher-order Hello World from {0]!", name); })
Я мог бы передать делегат в итератор.
delegate void Action(MyThing myThing);
private static void forEachThing(Action action)
{
using (var connection = new Connection())
{
action(new MyThing(connection));
}
}
yield
в C# специально для возврата битов итерационной коллекции. В частности, ваша функция должна возвращать IEnumerable<Thing>
или IEnumerable
на yield
для работы, и он предназначен для использования изнутри foreach
петли. Это очень специфическая конструкция в C#, и ее нельзя использовать так, как вы пытаетесь.
Я не уверен, что есть еще одна конструкция, которую вы могли бы использовать или нет, возможно, что-то с лямбда-выражениями.
вы можете GetThing
возьмите делегат, содержащий код для выполнения, а затем передайте анонимные методы из других функций.