Чтобы объяснить, как работают List<T>
и DataTable
(сноска вопроса), прочитайте следующее, но отметив, что:
List<T>
реализует IList
и имеет public T this[int index] {get;}
, который используется для разрешения метаданных
DataTable
реализует IListSource
, что обеспечивает таблицу по умолчанию DataView
; DataView
реализует IList
и ITypedList
для предоставления метаданных
Коллекции связываются в следующем порядке:
- источник проверен на
IListSource
; если доступно, IList
получается через GetList()
- в противном случае источник проверяется на
IList
; если недоступно, выдается исключение
затем запрашиваются метаданные для IList
:
-
IList
проверено на ITypedList
; если доступно, используется через GetProperties
-
IList
проверяется для общедоступного типизированного (необъектного) индексатора, т.е. public Foo this[int index] { get; }
- если он найден, Foo
подразумевается как тип и метаданные, полученные с помощью TypeDescriptor.GetProperties(Type)
- иначе первый элемент (если он не пустой) запрашивается для типа
GetType()
, а метаданные - TypeDescriptor.GetProperties(Type)
теперь у нас есть доступ к элементам (IList
) и их метаданным; дополнительная поддержка (необязательно) предоставляется через IBindingList
(обеспечивает двустороннее связывание и базовую сортировку и т. д.), IBindingListView
(обеспечивает расширенную сортировку, фильтрацию и т. д.), ICancelAddNew
и IRaiseItemChangedEvents
.
Для большинства распространенных сценариев (показать данные и отправить изменения обратно) List<T>
вполне подойдет; если вам нужно показать несвязанные обновления по мере их появления, BindingList<T>
помогает - но учтите, что для поддержки обновлений member уровня (в отличие от простого добавления / удаления / и т.д.) T
должен реализовывать INotifyPropertyChanged
Для справки, «метаданные» здесь означают «набор PropertyDescriptor
с» (1 на столбец / свойство), которые обеспечивают доступ к базовым данным (если предоставляется object
), и информацию об элементе сам (имя, тип и т. д.).