Почему инициализаторы коллекции C# работают таким образом?
Я смотрел на инициализаторы коллекции C# и обнаружил, что реализация очень прагматична, но также очень отличается от всего остального в C#
Я могу создать такой код:
using System;
using System.Collections;
class Program
{
static void Main()
{
Test test = new Test { 1, 2, 3 };
}
}
class Test : IEnumerable
{
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
public void Add(int i) { }
}
так как я выполнил минимальные требования к компилятору (реализовано IEnumerable
и public void Add
) это работает, но, очевидно, не имеет никакого значения.
мне было интересно, что помешало команде C# создать более строгий набор требований? Другими словами, почему, для компиляции этого синтаксиса компилятор не требует, чтобы тип реализовывал ICollection
? Это кажется больше в духе других функций C#.
3 ответа:
ваше наблюдение находится на месте - на самом деле, оно отражает одно, сделанное Мадсом Торгерсеном, Microsoft C# Language PM.
Mads сделал пост в октябре 2006 года на эту тему под названием что такое коллекция? в которой он написал:
признался, мы взорвали его в первом версия фреймворка с Система.Коллекции.Интерфейс ICollection, который это почти бесполезно. Но мы все исправили довольно хорошо, когда появились дженерики в сетях Framework 2.0 с: Система.Коллекции.Родовой.ICollection
позволяет добавлять и удалять элементы, перечислите их, посчитайте и проверьте для членства. очевидно, с тех пор, все бы реализовать ICollection
каждый раз они делают коллекцию, верно? Не очень. Вот как мы использовали LINQ, чтобы узнать о том, какие коллекции на самом деле есть, и как это заставило нас изменить наш язык дизайн в C# 3.0. оказывается, их всего 14 реализации
ICollection<T>
в рамках, но 189 классов, реализующихIEnumerable
и государственнойAdd()
метод.есть Скрытая польза от этого подхода-если бы они основывали его на
ICollection<T>
интерфейс, там был бы точно один поддерживаетсяAdd()
метод.напротив, подход, который они приняли, означает, что инициализаторы для коллекции просто формируют наборы аргументов для
Add()
методы.чтобы проиллюстрировать, давайте расширим ваш немного код:
class Test : IEnumerable { public IEnumerator GetEnumerator() { throw new NotImplementedException(); } public void Add(int i) { } public void Add(int i, string s) { } }
теперь вы можете написать это:
class Program { static void Main() { Test test = new Test { 1, { 2, "two" }, 3 }; } }
Я тоже думал об этом, и ответ, который меня больше всего удовлетворяет, заключается в том, что ICollection имеет много других методов, кроме Add, таких как: Clear, Contains, CopyTo и Remove. Удаление элементов или очистка не имеет ничего общего с возможностью поддержки синтаксиса инициализатора объекта, все, что вам нужно, это добавить().
Если бы фреймворк был разработан достаточно гранулярно, и был интерфейс ICollectionAdd, то у него был бы "идеальный" дизайн. Но я честно не думаю, что это будет добавили много значения, имея один метод на интерфейс. IEnumerable + Add кажется хакерским подходом, но когда вы думаете об этом, это лучшая альтернатива.
EDIT: это не единственный раз, когда C# подошел к проблеме с этим типом решения. Поскольку .NET 1.1, foreach использует duck typing для перечисления коллекции, все, что ваш класс должен реализовать, это GetEnumerator, MoveNext и Current. У Кирилла Осенкова есть post который также задает ваш вопрос.
(Я знаю, что я на 3 года опоздал на это, но я не был удовлетворен существующими ответами.)
почему для компиляции этого синтаксиса компилятор не делает требуется, чтобы тип реализовал ICollection?
я переверну ваш вопрос: какой смысл было бы, если бы у компилятора были требования, которые на самом деле не нужны?
не
ICollection
классы тоже могут извлечь выгоду из синтаксиса инициализатора коллекции. Рассмотрим классы, которые позволяют добавление в них данных без предоставления доступа к ранее добавленным данным.лично мне нравится использовать
new Data { { ..., ... }, ... }
синтаксис, чтобы добавить легкий, DSL-подобный взгляд на код моих модульных тестов.на самом деле, я бы предпочел ослабить требование, чтобы я мог использовать красивый синтаксис, даже не беспокоясь о реализации
IEnumerable
. Инициализаторы коллекции-это чистый синтаксический сахар для добавления (), они не должны требовать ничего другого.