Это условный оператор, и это не просто кратчайший способ написания операторов if.
Поскольку это выражение, которое возвращает значение, оно может использоваться как часть других выражений.
IEnumerable
не поддерживает это. Это дизайном. IEnumerable
отложенные вычисления использования для получения элементов Вы просите то, перед необходимостью в них.
, Если Вы хотите знать количество объектов, не выполняя итерации по ним, можно использовать ICollection<T>
, оно имеет Count
свойство.
Нет.
Вы видите, что информация, доступная где-нибудь в коде, записали?
Вы могли бы утверждать, что компилятор может "видеть", что существуют только два, но это означало бы, что он должен будет проанализировать каждый метод итератора, ищущий просто что определенный патологический случай. И даже если бы это сделало, как Вы считали бы его, учитывая пределы IEnumerable?
Я предложил бы назвать ToList. Да Вы делаете перечисление рано, но у Вас все еще есть доступ к Вашему списку объектов.
Нет, не в целом. Одна точка в использовании enumerables - то, что фактический набор объектов в перечислении не известен (заранее, или даже вообще).
У моего друга есть серия сообщений в блоге, которые приводят пример для того, почему Вы не можете сделать этого. Он создает функцию, которые возвращают IEnumerable, куда каждое повторение возвращает следующее простое число, полностью к ulong.MaxValue
, и следующий объект не вычисляется, пока Вы не просите его. Быстрый, вопрос о поп: сколько объектов возвращается?
Вот сообщения, но они довольно длинны:
IEnumerable не может рассчитать без итерации.
При "нормальных" обстоятельствах, это было бы возможно для классов, реализовав IEnumerable или IEnumerable< T> такие как List< T> для реализации Метода счета путем возврата List< T> свойство.Count. Однако Метод счета не является на самом деле методом, определенным на IEnumerable< T> или интерфейс IEnumerable. (Единственным то есть, на самом деле, является GetEnumerator.) И это означает, что определенная для класса реализация не может быть обеспечена для него.
Скорее количество это - дополнительный метод, определенный на статическом Счетном классе. Это означает, что это можно назвать на любом экземпляре IEnumerable< T> производный класс, независимо от реализации того класса. Но это также означает, что это реализовано в единственном месте, внешнем к любому из тех классов. Который, конечно, означает, что это должно быть реализовано способом, который абсолютно независим от внутренностей этого класса. Единственное такой способ сделать подсчет через повторение.
Просто добавив дополнительный некоторая информация:
Count()
расширение не всегда выполняет итерации. Рассмотрите Linq к Sql, куда количество переходит к базе данных, но вместо того, чтобы возвратить все строки, это дает команду Sql Count()
и возвраты тот результат вместо этого.
Кроме того, компилятор (или время выполнения) достаточно умен, что это назовет объекты Count()
метод, если это будет иметь тот. Таким образом, это не , как другие респонденты говорят, будучи абсолютно неосведомленными и всегда выполняющими итерации для подсчета элементов.
Во многих случаях, где программист просто проверяет if( enumerable.Count != 0 )
использование Any()
, дополнительный метод, как в if( enumerable.Any() )
намного более эффективен с отложенными вычислениями linq, поскольку это может закоротить, как только это может решить, что существуют любые элементы. Это - также больше читаемое
Here is a great discussion about lazy evaluation and deferred execution. Basically you have to materialize the list to get that value.
Going beyond your immediate question (which has been thoroughly answered in the negative), if you're looking to report progress whilst processing an enumerable, you might want to look at my blog post Reporting Progress During Linq Queries.
It lets you do this:
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += (sender, e) =>
{
// pretend we have a collection of
// items to process
var items = 1.To(1000);
items
.WithProgressReporting(progress => worker.ReportProgress(progress))
.ForEach(item => Thread.Sleep(10)); // simulate some real work
};
Alternatively you can do the following:
Tables.ToList<string>().Count;
The System.Linq.Enumerable.Count
extension method on IEnumerable
has the following implementation:
ICollection<T> c = source as ICollection<TSource>;
if (c != null)
return c.Count;
int result = 0;
using (IEnumerator<T> enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
result++;
}
return result;
So it tries to cast to ICollection
, which has a Count
property, and uses that if possible. Otherwise it iterates.
So your best bet is to use the Count()
extension method on your IEnumerable
object, as you will get the best performance possible that way.
Результат функции IEnumerable.Count () может быть неверным. Это очень простой пример для тестирования:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
namespace Test
{
class Program
{
static void Main(string[] args)
{
var test = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 };
var result = test.Split(7);
int cnt = 0;
foreach (IEnumerable<int> chunk in result)
{
cnt = chunk.Count();
Console.WriteLine(cnt);
}
cnt = result.Count();
Console.WriteLine(cnt);
Console.ReadLine();
}
}
static class LinqExt
{
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, int chunkLength)
{
if (chunkLength <= 0)
throw new ArgumentOutOfRangeException("chunkLength", "chunkLength must be greater than 0");
IEnumerable<T> result = null;
using (IEnumerator<T> enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
result = GetChunk(enumerator, chunkLength);
yield return result;
}
}
}
static IEnumerable<T> GetChunk<T>(IEnumerator<T> source, int chunkLength)
{
int x = chunkLength;
do
yield return source.Current;
while (--x > 0 && source.MoveNext());
}
}
}
Результат должен быть (7,7,3,3), но фактический результат (7,7,3,17)