#c# #generics #collections
#c# #общие #Коллекции
Вопрос:
List<T>
вместо этого имеет .Count
свойство, где в виде T<>
массивов .Length
. Я предполагаю, что это связано с тем, что массивы имеют фиксированную длину, тогда как другие — нет, но разница в синтаксисе все еще может расстраивать.
Поэтому, если вы выполняете рефакторинг из массива в список, он выдает «не содержит определения для .Ошибки «Length», и кажется пустой тратой времени на его изменение, когда .Count
и .Length
по сути одинаковы.
Есть ли хороший способ справиться с этим? Можно ли расширить, List<T>
чтобы добавить .Length
свойство, которое является псевдонимом для .Count
, например, и наоборот для универсального массива? И будет ли это плохой идеей по какой-либо причине?
Ответ №1:
Вы можете использовать Count
метод, предоставляемый LINQ.
Это оптимизировано для использования Count
свойства, предоставляемого ICollection<T>
интерфейсом, где это возможно (или не универсального ICollection
интерфейса тоже в .NET 4). Таким образом, массивы List<T>
и т.д. Будут оптимизированы.
var yourList = new List<string> { "the", "quick", "brown", "fox" };
int count1 = yourList.Count(); // uses the ICollection<T>.Count property
var yourArray = new[] { 1, 2, 4, 8, 16, 32, 64, 128 };
int count2 = yourArray.Count(); // uses the ICollection<T>.Count property
var yourEnumerable = yourArray.Where(x => x > 42);
int count3 = yourEnumerable.Count(); // no optimisation, iterates the sequence
В качестве альтернативы, если вам нужно какое-либо согласованное свойство count без риска повторения всей последовательности в неоптимизированном случае, вы могли бы создать свои собственные методы расширения. (Лично я бы не пошел по этому пути.)
int count4 = yourList.GetCount(); // uses the ICollection<T>.Count property
int count5 = yourArray.GetCount(); // uses the ICollection<T>.Count property
int count6 = yourEnumerable.GetCount(); // compile-time error
// ...
public static class CollectionExtensions
{
public static int GetCount<T>(this ICollection<T> source)
{
if (source == null) throw new ArgumentNullException("source");
return source.Count;
}
public static int GetCount(this ICollection source)
{
if (source == null) throw new ArgumentNullException("source");
return source.Count;
}
}
Комментарии:
1. Кроме того, любая коллекция, которая реализует не универсальное
ICollection
. И следует отметить, что массивы реализуют оба интерфейса, поэтому они получают преимущество логики сокращения.2. Не было ли у этого проблем с производительностью до .NET 4? Я думал, что это выполняется в цикле (даже без предиката), и поэтому потенциально было существенно медленнее. Простое выполнение Google «linq count slow» дает довольно много примеров. Похоже, это было бы решением для .Net 4, хотя и с оптимизациями.
3. @mikel: Насколько мне известно, Нет. Оно не оптимизировалось для не-универсальных коллекций
ICollection
до .NET 4, но я бы предположил, что для коллекции было бы относительно необычно реализовать genericIEnumerable<T>
, не-genericICollection
, но не genericICollection<T>
, что и потребовалось бы для того, чтобы новаяICollection
оптимизация вступила в силу там, где стандартнаяICollection<T>
оптимизация этого не сделала бы. (Конечно,Count
метод всегда будет немного медленнее, чем прямое использование любого базовогоCount
свойства, но ничего такого, что вы заметили бы при обычном повседневном использовании.)4. Но OP спрашивает, почему a
List
не содержитLength
свойства..Count
делает то же самое, ноLength
имеет O (1) временную завершенность
Ответ №2:
Вы могли бы поместить свой массив в переменную типа IList<T>
. (массивы реализуют этот интерфейс)
Затем вы можете использовать массив точно так же, как вы используете любой другой IList<T>
(хотя Add
и Remove
будут генерироваться исключения, поскольку массивы имеют фиксированную длину)
Ответ №3:
Вы можете использовать .Count()
метод как для списков, так и для массивов.
.Count()
Метод выполняется, если он доступен, затем он возвращается к традиционному .Length
.
Ответ №4:
Вы могли бы просто расширить общий список и добавить метод count, однако, если причина этого просто в том, что вы повторно разлагаете и не хотите обновлять до Count, я не советую этого делать. Нет необходимости расширять класс, если вы на самом деле ничего к нему не добавляете. Почему бы просто не обновить свой код, чтобы использовать Count вместо Length?