2016-11-17 3 views
2

В JavaScript можно создать генератор, который будет вести себя так:Генераторы в C#?

function* idMaker(){ 
    var index = 0; 
    while(true) 
    yield index++; 
} 

var gen = idMaker(); 

console.log(gen.next().value); // 0 
console.log(gen.next().value); // 1 
console.log(gen.next().value); // 2 

Что бы C# эквивалент выглядеть?

Интересно, будет ли это работать:

static System.Collections.Generic.IEnumerable<int> MakeId() 
{ 
    int index = 0; 
    while (true) 
    yield return index++; 
} 

, но от того, что я понимаю в C# до сих пор, выше не будет работать, как я намерен и вместо бесконечного цикла.

+0

Версия C# возвращается как функция, поэтому 'while (true)' заблокирует ваше приложение до тех пор, пока вы закончились из ОЗУ. –

+0

Почему это не будет вести себя так, как вы намерены? – Evk

+0

@ManfredRadlwimmer Я знаю, так что же эквивалент C#. У него даже есть генераторы? – theonlygusti

ответ

1

Ну, C# эквивалент вашего кода:

static void Main() 
{ 
    var enumerator = MakeId().GetEnumerator(); 

    enumerator.MoveNext(); 
    Console.WriteLine(enumerator.Current); // 0  
    enumerator.MoveNext(); 
    Console.WriteLine(enumerator.Current); // 1  
    enumerator.MoveNext(); 
    Console.WriteLine(enumerator.Current); // 2 

} 

static IEnumerable<int> MakeId() 
{ 
    int index = 0; 
    while (true) 
    yield return index++; 
} 

GetEnumerator возвращает перечислитель, который перебирает коллекцию.

+0

Изменение индекса с индексом ++ до '++ index' заставляет перечислитель начинать с' 1'. Вы закрываете это, проверяя «Текущий» перед первым «MoveNext()», что недопустимо. – hvd

+0

@hvd, хороший комментарий, соответственно изменен – Ofiris

6

Вы можете сделать то же самое с вашим MakeId следующим образом:

using (var gen = MakeId().GetEnumerator()) { 
    gen.MoveNext(); 
    Console.WriteLine(gen.Current); // 0 
    gen.MoveNext(); 
    Console.WriteLine(gen.Current); // 1 
    gen.MoveNext(); 
    Console.WriteLine(gen.Current); // 2 
} 

Если вам не нравится называть MoveNext все время, вы можете написать метод расширения:

public static class Extensions { 
    public static T NextValue<T>(this IEnumerator<T> enumerator) { 
     enumerator.MoveNext(); 
     return enumerator.Current; 
    } 
} 

Тогда это становится

using (var gen = MakeId().GetEnumerator()) {     
    Console.WriteLine(gen.NextValue()); // 0     
    Console.WriteLine(gen.NextValue()); // 1     
    Console.WriteLine(gen.NextValue()); // 2 
} 
+0

Первый пример здесь, в основном, что делает 'foreach'. –

+1

Да, но OP, похоже, хочет сделать это без foreach. Скажем, мне нужен один идентификатор, затем что-то делать, затем нужен второй идентификатор и т. Д. Или хотите хранить генератор в каком-то поле. – Evk

+0

Я просто указываю. Кто-то, кто изучает C#, может не знать об этом. –