2012-03-06 5 views
0

Я пытаюсь понять, что влияет на AsEnumerable() на мои данные при итерации по нему. У меня есть список флеш-памяти. Если я foreach над ним с первым вызовом ToList(), эта оценка силы и моя распечатка выглядит следующим образом (см код в нижней части этого поста, чтобы объяснить выход):AsEnumerable и как он влияет на доходность и SqlDataReader

entering da 
yield return 
yield return 
yield return 
exiting da 
doing something to aaron 
doing something to jeremy 
doing something to brendan 

Все имеет смысл. ToList() заставляет выходы в репозитории выполнять сначала в список, затем мы получаем нашу итерацию foreach. Все хорошо до сих пор.

Когда я делаю то же самое, за исключением использования AsEnumerable(), основываясь на том, что я прочитал о IQueryable (я понимаю, что это не IQueryable), я подумал бы эту оценку также силы, но это не так. Это выглядит следующим образом:

entering da 
yield return 
doing something to aaron 
yield return 
doing something to jeremy 
yield return 
doing something to brendan 
exiting da 

Как бы, если бы я даже не назвал AsEnumerable(), поэтому мой вопрос:

  1. Почему AsEnumerable ведут себя по-разному для в сборе памяти против LINQ к SQL и его IQueryable тип возврата?

  2. Как бы все это изменится, когда мое хранилище изменено с помощью SqlDataReader и делать yield return внутри считывателя (в то время вызова Read() метод). Будут ли полностью заполнены строки, исходящие из SqlServer, которые буферизуются в сетевом буфере клиентов, перед выполнением foreach (обычно yield здесь приведет к «паузе» в репо, в то время как каждая строка обрабатывается блоком foreach.Я знаю, звоню ли я ToList() первый в этом случае, я могу заставить оценку SqlDataReader, так же AsEnumerable сделать то же самое здесь

Примечания: Я не заинтересован в том сдача выхода в SqlDataReader является хорошей идеей, поскольку это может держите соединение открытым, я уже избил эту тему до конца :)

Вот мой тестовый код:

public class TestClient 
    { 
     public void Execute() 
     { 
      var data = MockRepo.GetData(); 

      foreach (var p in data.AsEnumerable()) //or .ToList() 
      { 
       Console.WriteLine("doing something to {0}", p.Name); 
      } 

      Console.ReadKey(); 
     } 
    } 

    public class Person 
    { 
     public Person(string name) 
     { 
      Name = name; 
     } 

     public string Name { get; set; } 
    } 

    public class MockRepo 
    { 
     private static readonly List<Person> items = new List<Person>(3) 
         { 
          new Person("aaron"), 
          new Person("jeremy"), 
          new Person("brendan") 
         }; 

     public static IEnumerable<Person> GetData() 
     { 
      Console.WriteLine("entering da"); 

      var enumerator = items.GetEnumerator(); 
      while (enumerator.MoveNext()) 
      { 
       Console.WriteLine("yield return"); 
       yield return enumerator.Current; 
      } 

      Console.WriteLine("exiting da"); 
     } 
    } 

ответ

4

AsEnumerable делает ничего, кроме изменить тип выражения для IEnumerable<T>. Когда он используется в запросе, как это:

var query = db.Customers 
       .Where(x => x.Foo) 
       .AsEnumerable() 
       .Where(x => x.Bar); 

... что просто означает, что вы будете использовать Queryable.Where для первого предиката (так, что преобразуется в SQL), и Enumerable.Where для второго предиката (так что оформленного в ваш код .NET).

Это не требует оценки. Он не делает ничего. Он даже не проверяет, вызвано ли оно null.

Для получения дополнительной информации см. Мой Edulinq blog post on AsEnumerable.

+0

Спасибо, queryable.where - enumerable.where различие, которое вы сделали, просто заставил все щелкнуть :) – AaronHS

1

@Jon Skeet уже опубликовал то, что делает AsEnumerable() - он просто меняет тип времени компиляции. Но зачем вы его используете?

По сути, изменив выражение из IQueryable к IEnumerable теперь вы можете использовать Linq к объектам (вместо IQueryable реализации вашим провайдером базы данных) без каких-либо ограничений - там не должно быть эквивалентным методом на стороне базы данных , поэтому вы можете свободно выполнять преобразование объектов, удаленные вызовы (если требуется) или любые манипуляции с строками.

Это сказал, что вы хотите сделать все фильтры вы можете в то время как вы все еще работаете в базе данных (IQueryable) - в противном случае вы бы привести все эти строки в память, которая будет стоить вам - и только потом использовать AsEnumerable() сделать ваши окончательные преобразования впоследствии.

0

Согласно MSDN documentation:

The AsEnumerable (Of TSource) (IEnumerable (Of TSource)) метод не имеет эффекта, кроме изменения типа во время компиляции источника из типа, который реализует IEnumerable (Of T) для IEnumerable (Of T).

Это не должно вызывать каких-либо оценок, просто намекните, что вы хотите использовать методы IEnumerable и некоторые другие реализации (IQueryable и т. Д.).