2013-03-15 2 views
0

Это очень простой (и бессмысленный) пример типа var, который имеет свойства перечислителя. Точка фрагмента состоит в том, чтобы поэкспериментировать с коллекцией с использованием строго типизированного класса, который реализует интерфейс IEnumerator.При использовании IEnumerator на строго типизированном классе он совершает много поездок на сервер

public class num { public int value { get; set; } } 

class Program { 

    private int[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 

    static void Main(string[] args) { 

     Program p = new Program(); 
     var numbers = selectNumbers(p.data); 


     foreach(num x in numbers) { 
      Console.WriteLine("Found {0}", x.value.ToString()); 
     } 

     Console.WriteLine("press [enter] to exit"); 
     Console.Read(); 
    } 

    static IEnumerable<num> selectNumbers(int[] x) { 
     //in production app the following would use a reader to get data from database 
     for(int i = 0; i < x.Length; i++) { 
      yield return new num { value = x[i] }; 
      Console.WriteLine("Found {0}", x[i].ToString()); // <<<(1) 
     } 
    } 
} 

Результаты, возвращенные на консоль, немного странные. Результаты, по-видимому, предполагают, что каждый раз, когда выполняется итерация цикла foreach, выполняется строка (1).

Означает ли это, что если бы я применил эту структуру к приложению настройки базы данных, где selectNumbers участвовал в получении контакта с нашей базой данных, будет ли он делать соединение каждый раз, когда используется IEnumerator? например каждый раз, когда он использует цикл foreach на строго типизированном num, будет ли он связываться с нашей базой данных? Результаты этого примера, похоже, предполагают, что это произойдет.

+0

['yield return'] (http://msdn.microsoft.com/en-us/library/vstudio/9k7k7cf0.aspx) вернет управление обратно вызывающему абоненту до тех пор, пока он не будет вызван или не будет исчерпан вернуться. – Romoku

ответ

0

Вот как yield return работ. Компилятор создает конечный автомат для реализации интерфейса IEnumerable<T>. Пример, который я показал вам с доступом к базе данных, был в this post. В этом примере состояние машина будет продолжаться, где он ранее оставил на предыдущей итерации, которая находится внутри цикла while, а не в начале метода:

static IEnumerable<MyModel> SelectTop100Models() 
{ 
    var connectionString = ConfigurationManager.ConnectionStrings["XXX"].ConnectionString; 
    using (var conn = new SqlConnection(connectionString)) 
    using (var cmd = conn.CreateCommand()) 
    { 
     conn.Open(); 
     cmd.CommandText = "SELECT top 100 * FROM x"; 
     using (var reader = cmd.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       // EXECUTION WILL CONTINUE FROM HERE AND NOT AT THE BEGINNING 
       // OF THE METHOD 
       yield return new MyModel 
       { 
        Id = reader.GetInt32(reader.GetOrdinal("ID")), 
        Name = reader.GetString(reader.GetOrdinal("Name")), 
       }; 
      } 
     } 
    } 
} 

Таким образом, вы не должны беспокоиться вообще о том, множественных подключения к базе данных. Этот код очень оптимизирован.

+0

ahh - так что мы могли бы теоретически переместить 'yield return' в другую позицию в методе' SelectTop100Models', и это переместило бы начальную точку для итераций foreach? – whytheq

Смежные вопросы