Имеет ли dot-сеть интерфейс, такой как IEnumerable с свойством Count?
Имеет ли точка net интерфейс, такой как IEnumerable с свойством count? Я знаю об интерфейсах, таких как IList и ICollection, которые предлагают свойство Count, но похоже, что эти интерфейсы были сначала разработаны для изменяемых структур данных, а использование в качестве интерфейса только для чтения кажется запоздалым - наличие поля IsReadOnly и мутаторов, бросающих исключения когда это свойство верно, IMO является достаточным доказательством этого.
В настоящее время я использую настраиваемый интерфейс IReadOnlyCollection (см. мой собственный ответ на этот пост), но я был бы рад узнать о других альтернативных подходах.
Ответы
Ответ 1
Ключевое различие между семейством ICollection и семейством IEnumerable заключается в отсутствии уверенности относительно количества присутствующих предметов (нередко элементы будут сгенерированы/загружены/гидратированы по мере необходимости) - в некоторых случаях Enumerable не может когда-либо заканчивая получение результатов, поэтому граф отсутствует.
Получение и добавление графа возможно в зависимости от ваших требований, но оно противоречит этому духу, который является целью ICollection - совокупности вещей, которые там есть.
Другим способом может быть использование метода System.Linq.Enumerable.Count, т.е.
using System.Linq;
class X
{
void Y(IEnumerable<int> collection)
{
int itemCount = collection.Count();
}
}
или используйте (System.Linq.Enumerable).ToList(), чтобы вытащить все элементы из перечислителя в коллекцию и работать оттуда.
(Также, чтобы ответить на ваш комментарий перед тем, как иметь 50 rep: бит бит .Count() - это вызов метода расширения в классе расширения System.Linq.Enumerable - метод расширения доступен для всех вещей, которые выводятся из IEnumerable, потому что у кода есть "использование System.Linq", который привносит методы расширения во все классы в этом пространстве имен в область видимости - в этом случае это в классе Enumerable. Если вы находитесь в VS, нажатие F12 приведет вас к определение SLEnumerable. BTW С# In Depth - это фантастическая книга для обучения LINQ правильно - ее токарь страницы действительно помогает вам получить всю картину по сравнению с изучением бит LINQ по частям)
Ответ 2
Как и для .Net 4.5, для этого есть два новых интерфейса: IReadOnlyCollection<T>
и IReadOnlyList<T>
.
IReadOnlyCollection<T>
есть IEnumerable<T>
с добавленным свойством Count
, IReadOnlyList<T>
также добавляет индексирование.
Ответ 3
Принимая во внимание некоторые комментарии, я решил пойти с классом-оболочкой, реализующим пользовательский интерфейс...
interface IReadOnlyCollection<T> : IEnumerable<T>
{
int Count { get; }
}
//This can now be not misused by downcasting to List
//The wrapper can also be used with lists since IList inherits from ICollection
public class CollectionWrapper<T> : IReadOnlyCollection<T>
{
public CollectionWrapper(ICollection<T> collection)
{
_collection = collection;
}
public int Count
{
get
{
return _collection.Count;
}
}
public IEnumerator<T> GetEnumerator()
{
return (IEnumerator<T>)_collection.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)((IEnumerable)_collection).GetEnumerator();
}
////////Private data///////
ICollection<T> _collection;
}
class Program
{
static void Main(string[] args)
{
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
CollectionWrapper<int> collection = new CollectionWrapper<int>(list);
Console.WriteLine("Count:{0}", collection.Count);
foreach (var x in collection)
{
Console.WriteLine(x);
}
foreach (var x in (IEnumerable)collection)
{
Console.WriteLine(x);
}
}
}
Спасибо всем за ваши предложения.
Изменить: Теперь нельзя использовать недопустимое преобразование в список (или что-то еще).
Ответ 4
Похоже, вы действительно хотите ReadOnlyCollection<T>
- выставить его как IList<T>
, но, обернув исходный список, как это вы просто получите оболочку только для чтения с соответствующим счетчиком.
Ответ 5
IList может возвращать IsReadOnly как true, что отмечает коллекцию как readonly. Кроме этого, я боюсь, я не знаю ничего подходящего.
Ответ 6
Поскольку это интерфейс, вам нужно было бы реализовать свойство Count самостоятельно, почему бы вам не создать новый интерфейс, который наследует IEnumerator и добавить свойство Count?
Ответ 7
IList
или ICollection
- это путь, если вы хотите использовать стандартные интерфейсы.
Обратите внимание, что вы можете "спрятать" методы, требуемые интерфейсом, если вы не хотите их в открытом интерфейсе вашего класса - например, поскольку бессмысленно добавлять вещи в коллекцию readonly, вы можете это сделать:
void ICollection<DataType>.Add(DataType item)
{
throw new NotSupportedException();
}
public DataType this[int index]
{
get { return InnerList[index]; }
}
DataType IList<DataType>.this[int index]
{
get { return this[index]; }
set { throw new NotSupportedException(); }
}
и др.
Ответ 8
Вы можете получить. Включите IEnumerable с помощью метода расширения, если вы добавите ссылку на System.Linq(в любом случае 3.5).
Ответ 9
Массив может быть передан в IList, что делает IList ReadOnly == true:)
Ответ 10
Как упоминает Джон Скит, вам гораздо лучше использовать System.Collections.ObjectModel.ReadOnlyCollection вместо создания собственного класса-оболочки.
Затем вы можете реализовать свой образец следующим образом:
class Program {
static void Main(string[] args) {
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
ReadOnlyCollection<int> collection = new ReadOnlyCollection<int>(list);
Console.WriteLine("Count:{0}", collection.Count);
foreach (var x in collection) {
Console.WriteLine(x);
}
foreach (var x in (IEnumerable)collection) {
Console.WriteLine(x);
}
}
}