2008-08-19 6 views
152

Я знаю, что IList - это интерфейс, а List - конкретный тип, но я до сих пор не знаю, когда использовать его. То, что я делаю сейчас, - это то, что мне не нужны методы Sort или FindAll, которые я использую для интерфейса. Я прав? Есть ли лучший способ решить, когда использовать интерфейс или конкретный тип?Когда использовать IList и когда использовать Список

ответ

141

Есть два правила я следую:

  • Примите наиболее базовый тип, который будет работать
  • Return богатейшим типа вашего пользователю будет нуждаться

So при написании функции или методы, берет коллекцию, записывает ее не для получения списка, а для IList <T>, ICollection <T>, или IEnumerable <T>. Общие интерфейсы по-прежнему будут работать даже для гетерогенных списков, поскольку System.Object также может быть T. Это поможет вам избавиться от головной боли, если вы решите использовать стеки или другую структуру данных дальше по дороге. Если все, что вам нужно сделать в функции, это через него, IEnumerable <T> - это действительно все, о чем вы должны просить.

С другой стороны, при возврате объекта из функции вы хотите предоставить пользователю самый богатый возможный набор операций без их обхода. Поэтому в этом случае, если это список <T>, верните копию в виде списка <T>.

+32

Вы не должны обрабатывать типы ввода/вывода по-разному. Типы ввода и вывода должны * оба * быть самым основным (предпочтительно, интерфейсом), который будет поддерживать потребности клиентов. Инкапсуляция основывается на том, чтобы как можно меньше рассказывать клиентам о реализации вашего класса. Если вы вернете конкретный список, вы не сможете перейти к другому лучшему типу, не заставляя всех ваших клиентов повторно компилировать/обновлять. – Ash 2010-09-12 08:53:59

+11

Я не согласен с 2 правилами ...Я бы использовал самый примитивный тип и специальность, возвращаясь в этом случае IList (лучше IEnumarable), и вы должны работать со списком в своей функции внутри. Затем, когда вам нужно «добавить» или «сортировать», затем используйте «Коллекция», если вам нужно больше, затем используйте «Список». Таким образом, мое твердое правило: START всегда с IENumarable, и если вам нужно больше, то расширяйтесь ... – ethem 2013-04-26 18:25:27

+2

Для вашего удобства «два правила» имеют имя: [принцип надежности (aka Postel's law)] (https: // en .wikipedia.org/вики/Robustness_principle). – easoncxz 2015-06-13 11:12:20

4

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

Например, у вас есть класс Person и класс Group. У экземпляра Group много людей, поэтому список здесь имеет смысл. Когда я объявляю объект списка в Group, я буду использовать IList<Person> и создать его как List.

public class Group { 
    private IList<Person> people; 

    public Group() { 
    this.people = new List<Person>(); 
    } 
} 

И, если вы даже не нужно все в IList вы всегда можете использовать IEnumerable тоже. С современными компиляторами и процессорами я не думаю, что на самом деле есть какая-то разница в скорости, так что это скорее вопрос стиля.

+3

Почему бы не сделать это просто списком в первую очередь? Я до сих пор не понимаю, почему вы получаете бонус от ILIP, а затем в конструкторе, который вы делаете в List <> – chobo2 2011-12-19 20:56:50

+0

Согласен, если вы явно создаете объект List , тогда вы теряете преимущество интерфейса? – 2017-09-18 13:15:48

1

В ситуациях, когда я обычно сталкиваюсь, я редко использую IList.

Обычно я просто использовать его в качестве аргумента метода

void ProcessArrayData(IList almostAnyTypeOfArray) 
{ 
    // Do some stuff with the IList array 
} 

Это позволит мне сделать общую обработку практически любого массива в рамках .NET, если он не использует IEnumerable и не IList, которая происходит иногда.

Это действительно сводится к той функциональности, в которой вы нуждаетесь. Я бы предложил использовать класс List в большинстве случаев. IList лучше всего, когда вам нужно создать собственный массив, который может содержать некоторые очень специфические правила, которые вы хотите инкапсулировать в коллекцию, чтобы вы не повторялись, но все же хотите, чтобы .NET распознала его как список.

5

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

1

Вы должны использовать интерфейс только в том случае, если вам это необходимо, например, если ваш список включен в реализацию IList, отличную от List. Это верно, если, например, вы используете NHibernate, который бросает ILists в объект сумки NHibernate при извлечении данных.

Если List - единственная реализация, которую вы когда-либо использовали для определенной коллекции, не стесняйтесь объявлять ее как конкретную реализацию List.

9

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

Для коллекций вы должны, по возможности, использовать IEnumerable. Это дает максимальную гибкость, но не всегда подходит.

+1

Всегда лучше ** принять ** самый низкий базовый тип. Возвращение - это совсем другая история. Выберите варианты, которые могут быть полезны. Итак, вы думаете, что ваш клиент может захотеть использовать индексированный доступ? Храните их в `ToList()` -в возвращаемом `IEnumerable `, который уже был списком, и вместо этого возвращает `IList ``. Теперь клиенты могут извлечь выгоду из того, что вы можете предоставить без усилий. – Timo 2016-10-24 12:06:52

24

Я согласен с рекомендацией Ли для принятия параметров, но не с возвратом.

Если вы укажете свои методы для возврата интерфейса, это означает, что вы можете свободно изменять точную реализацию позже, не используя метод потребления, который когда-либо знал. Я думал, что мне никогда не нужно будет меняться из списка < T>, но потом нужно было изменить использование специальной библиотеки списков для дополнительных функций, которые она предоставила. Потому что я только вернул IList < T> Никто из людей, которые использовали библиотеку, не должен был менять свой код.

Конечно, это необходимо применять только к методам, которые внешне видимы (т. Е. Общедоступные методы). Я лично использую интерфейсы даже во внутреннем коде, но поскольку вы можете самостоятельно изменить весь код, если вы делаете нарушения, это не является абсолютно необходимым.

50

рекомендации Microsoft, как проверяются FxCop препятствовать использованию Список <T> в общественных API, - предпочитают IList <T>.

Кстати, я теперь почти всегда объявить одномерные массивы IList <T>, что означает, что я могу последовательно использовать .Count свойство IList < Т >, а не Array.length. Например:

public interface IMyApi 
{ 
    IList<int> GetReadOnlyValues(); 
} 

public class MyApiImplementation : IMyApi 
{ 
    public IList<int> GetReadOnlyValues() 
    { 
     List<int> myList = new List<int>(); 
     ... populate list 
     return myList.AsReadOnly(); 
    } 
} 
public class MyMockApiImplementationForUnitTests : IMyApi 
{ 
    public IList<int> GetReadOnlyValues() 
    { 
     IList<int> testValues = new int[] { 1, 2, 3 }; 
     return testValues; 
    } 
} 
3

Вы чаще всего лучше использовать наиболее общий полезный тип, в данном случае IList или даже лучше в IEnumerable интерфейс, так что вы можете переключить реализацию удобно на более позднее время.

Однако, в .NET 2.0 существует раздражающая вещь - у IList нет метода Sort(). Вы можете использовать прилагаемый адаптер вместо:

ArrayList.Adapter(list).Sort() 
16

IEnumerable вы должны попробовать и использовать наименее определенный тип, который соответствует вашим целям.IEnumerable менее специфичен, чем IList Вы можете использовать IEnumerable, когда вы хотите перебрать элементы в коллекции

IList IList реализует IEnumerable Вы должны использовать IList, когда вам нужен доступ по индексу к вашей коллекции, добавлять и удалять элементы и т.д ..

Список Список реализует IList

2

объект ALIST позволяет создать список, добавить вещи к нему, удалить его, обновить его, индекс в нем и т.д. Список является используется всякий раз, когда вам просто нужен общий список, в котором вы указываете тип объекта в нем, и все.

С другой стороны, IList является интерфейсом. В принципе, если вы хотите создать свой собственный тип List, скажите класс списка BookList, вы можете использовать интерфейс, чтобы дать вам базовые методы и структуру для вашего нового класса. IList предназначен, когда вы хотите создать свой собственный специальный класс, который реализует List.

Другое отличие: IList - это интерфейс и не может быть создан. Список - это класс и может быть создан. Это означает:

IList<string> MyList = new IList<string>(); 

List<string> MyList = new List<string> 
24

Там важная вещь, что люди всегда, кажется, упускать из вида:

Вы можете передать простой массив что-то, принимающий IList<T> параметра, а затем вы можете позвонить IList.Add() и получите выполнение исключение:

Unhandled Exception: System.NotSupportedException: Collection was of a fixed size.

Например, рассмотрим следующий код:

private void test(IList<int> list) 
{ 
    list.Add(1); 
} 

Если вы называете это следующим образом, вы получите исключение во время выполнения:

int[] array = new int[0]; 
test(array); 

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

По этой причине, если вы звоните IList<T>.Add(), вы можете потребовать List<T> вместо IList<T>.

Смежные вопросы