Зачем создавать класс, производный от общего списка (.NET)?

2

В чем разница между:

Список <MyType> MyList;

и

myList: List <MyType>

Очевидно, что первый - это список, а второй - класс. Но мой вопрос заключается в том, что преимущество второго по сравнению с первым.

Теги:
generics

7 ответов

8
Лучший ответ

Последний дает вам возможность иметь функцию, которая принимает myList, а не только список. Это также означает, что если тип myList изменяется (возможно, в отсортированный список), вам не нужно менять код в любом месте. Поэтому вместо объявления List<myType> everwhere, а затем, чтобы изменить их, если у вас есть MyList объекты повсюду, вы золотые.

Его также синтаксическая разница. Имеет ли myList список, или это список?

Я бы склонялся к тому, чтобы иметь MyList : List<MyType>, если он используется обычно в вашей программе.

  • 0
    Здесь нет никакого различия. Оба являются списками. Если бы вы хотели иметь a-a, вы бы написали что-то более похожее на: public class MyList { private List<MyType> mytypes = new List<MyType>(); }
3

Состав объекта текст ссылки

против.

Наследование классов текст ссылки

3

Список <MyType> myList - это экземпляр универсального типа List, который может содержать элементы MyType (или любых типов, полученных из MyType).

var myTypeInstance = new MyType();
var myList = new List<MyType>;
myList.Add(myTypeInstance);

myList: List <MyType> - это новый тип, который наследует List, из которого вы можете сделать несколько экземпляров:

var myTypeInstance = new MyType();
var myCollectionVariable = new myList();
myCollectionVariable.Add(myTypeInstance);

Основное преимущество последнего над первым заключается в том, что если вы хотите иметь некоторые методы, которые действуют в списке, вы можете поместить их в свой класс, а не хранить их в библиотеке "помощник" или "полезность", например

class myList : List<MyType>
{
  public void DoSomethingToAllMyTypesInList()
  {
    ...
    ...
  }
}
2

Руководства по проектированию Microsoft (FxCop и VS Code Analysis) не рекомендуют наследовать открытые для публики классы из списка <T> . Вместо этого вы можете наследовать от Collection <T> , как описано в в этом сообщении в блоге.

Эти рекомендации не обязательно релевантны для частных сборок или внутренних классов.

Несколько причин, по которым вы, возможно, захотите наследовать от Collection <T> или List <T> ,:

  • Таким образом, вы можете добавить пользовательских членов, специфичных для приложения, в свой класс коллекции.

  • Итак, вы можете создать класс коллекции ComVisible (вы не можете публиковать общий список непосредственно для COM, но вы можете выставить производный класс).

Кстати, правила именования также рекомендуют вам называть ваш производный класс суффиксом "Коллекция", т.е.

MyTypeCollection : List<MyType> // or : Collection<MyType>, IList<MyType>

а не

MyList : List<MyType> // or : Collection<MyType>, IList<MyType>
  • 0
    +1 Список <T> также не имеет виртуальных методов для правильного расширения.
2

Последний - новый класс, который наследуется от базы, но отличается. Самое очевидное отличие состоит в том, что у него нет одинаковых конструкторов, но вы также столкнетесь с проблемами с потоковой передачей.

Это недостатки. Преимущество состоит в том, что вы можете добавить некоторые из ваших собственных методов. Даже тогда, я бы подумал об использовании сдерживания, с has-отношения вместо is-a.

  • 0
    В C # 3 вы можете использовать методы расширения для добавления методов в List <MyType>, так что это преимущество больше не действует.
  • 0
    Половина правда. Вы можете добавлять методы, но на самом деле они статичны, поэтому если вам нужны методы, которые зависят от дополнительных базовых полей, вы застряли с наследованием.
2

Я бы предпочел не наследовать реализацию там, где это возможно. Он имеет свои применения, но если это не совсем необходимо, то это не стоит.

Главный ответ на ваш вопрос заключается в том, что, наследуя List<T>, вы делаете все его методы общедоступными по умолчанию. Обычно при написании нового класса требуется инкапсуляция. Вы не хотите, чтобы внутренние просачивались. Например, предположим, что вы хотите создать поточно-безопасный контейнер. Если вы наследуете от потока-неосведомленного контейнера, ваши клиенты смогут использовать открытый интерфейс базового класса для обхода любой блокировки, которую вы пытаетесь вставить.

Другая популярная ошибка возникает, когда вы часто используете определенный тип контейнера, заставляя попробовать и использовать наследование, чтобы сделать короткое имя для него:

class ShortName : Dictionary<string, List<string>> { };

Но это не то, что вы сделали - вы создали совершенно новый тип. Это означает, что если у вас есть другая библиотека, которая может создать правильную структуру данных, она не будет напрямую использоваться вашим кодом; вам придется сначала скопировать его в ShortName. Например, Linq, который может легко построить Dictionary<string, List<string>> из очень читаемого функционального выражения, заканчивая ToDictionary.

Итак, сделайте следующее:

using ShortName = Dictionary<string, List<string>>;

Теперь у вас короткий псевдоним для unweildy typename, но вы на самом деле все еще используете один и тот же тип.

  • 0
    Особенно полезно при использовании Linq ToDictionary или ToList
1

Некоторые люди находят преимущества в абстрагировании структур данных от их логики приложений. Если вы решите, что общий список больше не является лучшей структурой данных для представления MyList, вы можете изменить свою реализацию MyList, и до тех пор, пока ваш интерфейс будет таким же, вам не нужно обновлять какой-либо другой код.

Однако во многих ситуациях это убивает.

Есть также семантические преимущества для работы с абстрактным типом данных, а не с оригиналом, хотя тип списка стирает линию. Это более очевидно при работе со структурой данных словаря. Если вы закроете словарь в пользовательском типе коллекции и поместите ключи и значения в качестве свойств. вы можете написать код, который больше похож на бизнес-логику, которую вы реализуете.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню