Наследование List <T>для реализации коллекций плохая идея? - PullRequest
12 голосов
/ 20 сентября 2010

Однажды я прочитал статью Imaar Spaanjars о том, как создавать трехуровневые приложения. (http://imar.spaanjaars.com/416/building-layered-web-applications-with-microsoft-aspnet-20-part-1), который некоторое время лежал в основе моего кодирования.

Таким образом, я реализую коллекции так, как он это сделал, наследуя List<T>. Поэтому, если у меня есть класс с именем Employee, для реализации коллекции у меня также будет класс Employees, как показано ниже.

class Employee
{
   int EmpID {get;set;}
   string EmpName {get;set;}  

}

class Employees : List<Employee>
{
   public Employees(){}
}

Я никогда не подвергал сомнению это, поскольку это сделало работу для меня. Но теперь, когда я начал пробовать несколько вещей, я не уверен, что это правильный подход.

например. если я хочу получить подмножество сотрудников, например

 Employees newEmployees = (Employees) AllEmployees.FindAll(emp => emp.JoiningDate > DateTime.Now);

Это вызывает исключение System.InvalidCastException. Однако, если я использую следующее, то это не проблема.

List<Employee> newEmployees = AllEmployees.FindAll(emp => emp.JoiningDate > DateTime.Now);

Итак, как мне реализовать Employees, чтобы мне не приходилось явно использовать List<Employee> в моем DAL или BLL? Или, может быть, как мне избавиться от InvalidCastexception?

Ответы [ 4 ]

18 голосов
/ 20 сентября 2010

Я бы не унаследовал от List<T> - он привносит подобные проблемы и на самом деле не помогает (так как нет virtual методов для переопределения). Я бы либо использовал List<T> (или более абстрактный IList<T>), либо чтобы ввести полиморфизм Collection<T> имеет виртуальных методов.

как примечание; В таких вещах, как FindAll, вы также можете найти полезные аналоги параметров LINQ (например, .Where()); в частности, они будут работать для любого IList<T> (или IEnumerable<T>), а не только для List<T> и подклассов.

10 голосов
/ 20 сентября 2010

Какую выгоду вы получаете от подкласса List<Employee>? Если это ничего не добавляет, то это лишнее раздувание кода. Если вы не показываете методы или применяете контракты через конструктор, который вы не показали здесь, то это может быть веской причиной для подкласса.

С точки зрения решения вашей проблемы с кастингом, вы не можете снизить рейтинг от List<Employee> до Employees, так как List<Employee> не наследуется от Employees. Если вам нужно вернуть Employees с вашими критериями, то лучше всего инкапсулировать вызов и вставить возвращенные элементы списка в ваш собственный объект Employees. Это кажется пустой тратой времени, если, как я сказал выше, у вас нет веских причин для подкласса List<Employee>.

Лично я бы попытался использовать IList<T> везде, где это возможно, и не создавать подклассы, если у них нет причин для существования.

4 голосов
/ 20 сентября 2010

Простое эмпирическое правило - начать с СОСТАВА (например, обернуть сотрудников вокруг общей коллекции), а НЕ НАСЛЕДОВАТЬ. Начать с наследственного дизайна - нарисовать себя в углу. Композиция более гибкая и модифицируемая.

4 голосов
/ 20 сентября 2010

Я бы лично сохранил список как член объекта-контейнера, и, если необходимо, предоставил get для доступа к самому списку.

class MyCollection<T> 
{
    List<T> _table;
    public List<T> Table
    {
        get
        {
            return _table;
        }
    }
    // ... other access/utility functions common for all tables 
    //     (CRUD for example)
}

class Employees : MyCollection<Employee>
{
    // ... yet more methods 
}

Я должен признать, что сделал это, чтобы обеспечить себя такими методами, как:

T FindById(int id);
void Add(T entity);
void Remove(T entity);

для базового класса и:

T[] GetEmployeesBy(your_filter_here);

Я (все еще) использую .net 2.0, поэтому у меня нет linq - возможно, причина в этом здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...