Je les ai vus utilisés de la même manière et je crains de m'engager dans une voie de conception irréversible si je ne comprends pas mieux cela. En outre, j'utilise .NET.
Je les ai vus utilisés de la même manière et je crains de m'engager dans une voie de conception irréversible si je ne comprends pas mieux cela. En outre, j'utilise .NET.
Réponses:
Collection<T>
est un wrapper personnalisable IList<T>
. Bien qu'il IList<T>
ne soit pas scellé, il ne fournit aucun point de personnalisation. Collection<T>
Les méthodes de sont par défaut déléguées aux IList<T>
méthodes standard , mais peuvent être facilement remplacées pour faire ce que vous voulez. Il est également possible de connecter des événements à l'intérieur d'un Collection<T>
qui, je ne pense pas, pourrait être fait avec un IList.
En bref, il est beaucoup plus facile de l'étendre après coup, ce qui pourrait potentiellement signifier beaucoup moins de refactoring.
IList
, IList<T>
, List<T>
etc. Bref, vous ne savez pas si elle sera appelée. Le polymorphisme résout ce problème.
ObservableCollection<T>
titre d'exemple où les méthodes sont remplacées pour notifier les modifications.
En C #, il existe trois concepts pour représenter un sac d'objets. Par ordre croissant de fonctionnalités, ce sont:
Enumerable n'a pas d'ordre. Vous ne pouvez pas ajouter ou supprimer des éléments de l'ensemble. Vous ne pouvez même pas obtenir le nombre d'articles dans l'ensemble. Il vous permet strictement d'accéder à chaque élément de l'ensemble, l'un après l'autre.
La collection est un ensemble modifiable. Vous pouvez ajouter et supprimer des objets de l'ensemble, vous pouvez également obtenir le nombre d'éléments dans l'ensemble. Mais il n'y a toujours pas d'ordre, et parce qu'il n'y a pas d'ordre: aucun moyen d'accéder à un élément par index, ni aucun moyen de trier.
La liste est un ensemble ordonné d'objets. Vous pouvez trier la liste, accéder aux éléments par index, supprimer des éléments par index.
En fait, quand on regarde les interfaces pour ceux-ci, ils s'appuient les uns sur les autres:
interface IEnumerable<T>
GetEnumeration<T>
interface ICollection<T> : IEnumerable<T>
Add
Remove
Clear
Count
interface IList<T> = ICollection<T>
Insert
IndexOf
RemoveAt
Lors de la déclaration de variables ou de paramètres de méthode, vous devez choisir d'utiliser
basé sur conceptuellement, vous devez faire avec l'ensemble des objets.
Si vous avez juste besoin de pouvoir faire quelque chose sur chaque objet d'une liste, il vous suffit de IEnumerable
:
void SaveEveryUser(IEnumerable<User> users)
{
for User u in users
...
}
Vous ne vous inquiétez pas si les utilisateurs sont conservés dans un List<T>
, Collection<T>
, Array<T>
ou toute autre chose. Vous n'avez besoin que de l' IEnumerable<T>
interface.
Si vous avez besoin de pouvoir ajouter, supprimer ou compter les éléments d'un ensemble, utilisez une collection :
ICollection<User> users = new Collection<User>();
users.Add(new User());
Si vous vous souciez d'un ordre de tri et que vous avez besoin que l'ordre soit correct, utilisez une liste :
IList<User> users = FetchUsers(db);
Sous forme de graphique:
| Feature | IEnumerable<T> | ICollection<T> | IList<T> |
|------------------------|----------------|----------------|----------|
| Enumerating items | X | X | X |
| | | | |
| Adding items | | X | X |
| Removing items | | X | X |
| Count of items | | X | X |
| | | | |
| Accessing by index | | | X |
| Removing by indexx | | | X |
| Getting index of item | | | X |
Les List<T>
et Collection<T>
in System.Collections.Generic
sont deux classes qui implémentent ces interfaces; mais ce ne sont pas les seules classes:
ConcurrentBag<T>
est un sac d'objets ordonné ( IEnumerable<T>
)LinkedList<T>
est un sac dans lequel vous n'êtes pas autorisé à accéder aux éléments par index ( ICollection
); mais vous pouvez ajouter et supprimer arbitrairement des éléments de la collectionSynchronizedCollection<T>
dans une collection ordonnée, où vous pouvez ajouter / supprimer des éléments par indexAinsi, vous pouvez facilement changer:
IEnumerable<User> users = new SynchronizedCollection<User>();
SaveEveryUser(users);
Choisissez le concept dont vous avez besoin, puis utilisez la classe correspondante.
ICollection<T>
et IList<T>
. Différentes implémentations concrètes peuvent se comporter différemment. Par exemple, si vous accédez à un List<T>
via son IEnumerable<T>
interface, vous n'avez aucun moyen d'ajouter, de supprimer, de trier ou de compter des éléments dans la liste.
List<T>
est destiné à un usage interne dans le code de l'application. Vous devez éviter d'écrire des API publiques qui acceptent ou renvoient List<T>
(envisagez d'utiliser une superclasse ou une interface de collection à la place).
Collection<T>
sert une classe de base pour les collections personnalisées (bien qu'elle puisse être utilisée directement).
Pensez à utiliser Collection<T>
dans votre code, sauf si List<T>
vous avez besoin de fonctionnalités spécifiques .
Ce ne sont que des recommandations.
[Adapté de: Framework Design Guidelines, deuxième édition]
Dictionary<string, List<string>>
retourner List<string>
est très bien, puisque l'état du dictionnaire encapsule uniquement les identités des listes qu'il contient, plutôt que leur contenu.
List<T>
est un récipient très souvent vu, car il est tellement polyvalent (avec beaucoup de méthodes pratiques comme Sort
, Find
, etc.) - mais n'a pas des points d'extension si vous voulez remplacer l' un des comportements (éléments de contrôle à l' insertion, par exemple).
Collection<T>
est un wrapper autour de tout IList<T>
(par défaut List<T>
) - il a les points d'extension ( virtual
méthodes), mais pas autant de méthodes de support que Find
. En raison de l'indirection, il est légèrement plus lent que List<T>
, mais pas de beaucoup.
Avec LINQ, les méthodes supplémentaires en List<T>
deviennent moins importantes, puisque LINQ-à-objets tend à leur fournir de toute façon ... par exemple First(pred)
, OrderBy(...)
etc.
La liste est plus rapide.
Faites par exemple
private void button1_Click(object sender, EventArgs e)
{
Collection<long> c = new Collection<long>();
Stopwatch s = new Stopwatch();
s.Start();
for (long i = 0; i <= 10000000; i++)
{
c.Add(i);
}
s.Stop();
MessageBox.Show("collect " + s.ElapsedMilliseconds.ToString());
List<long> l = new List<long>();
Stopwatch s2 = new Stopwatch();
s2.Start();
for (long i = 0; i <= 10000000; i++)
{
l.Add(i);
}
s2.Stop();
MessageBox.Show("lis " + s2.ElapsedMilliseconds.ToString());
}
sur ma machine List<>
est presque deux fois plus rapide.
Éditer
Je ne peux pas comprendre pourquoi les gens votent contre cela. Tant sur ma machine de travail que sur ma machine domestique, le code List <> est 80% plus rapide.
La liste représente une collection où l'ordre des éléments est important. Il prend également en charge les méthodes de tri et de recherche. La collecte est une structure de données plus générale qui fait moins d'hypothèses sur les données et prend également en charge moins de méthodes pour les manipuler. Si vous souhaitez exposer une structure de données personnalisée, vous devez probablement étendre la collection. Si vous avez besoin de manipuler des données sans exposer la structure de données, une liste est probablement le moyen le plus pratique.
C'est l'une de ces questions des écoles supérieures. Une collection de T est une sorte d'abstrait; il peut y avoir une implémentation par défaut (je ne suis pas un gars .net / c #) mais une collection aura des opérations de base comme ajouter, supprimer, itérer, etc.
La liste de T implique quelques spécificités sur ces opérations: add devrait prendre un temps constant, remove devrait prendre un temps proportionnel au nombre d'éléments, getfirst devrait être un temps constant. En général, une liste est une sorte de collection, mais une collection n'est pas nécessairement une sorte de liste.
Hanselman Speaks : " Collection<T>
ressemble à une liste, et il en a même une en List<T>
interne. CHAQUE méthode est déléguée à l'interne List<T>
. Elle inclut une propriété protégée qui expose le List<T>
."
EDIT: Collection<T>
n'existe pas dans System.Generic.Collections .NET 3.5. Si vous migrez de .NET 2.0 vers 3.5, vous devrez changer du code si vous utilisez beaucoup d' Collection<T>
objets, sauf si je manque quelque chose d'évident ...
EDIT 2: Collection<T>
est maintenant dans l'espace de noms System.Collections.ObjectModel dans .NET 3.5. Le fichier d'aide dit ceci:
«L'espace de noms System.Collections.ObjectModel contient des classes qui peuvent être utilisées comme collections dans le modèle objet d'une bibliothèque réutilisable. Utilisez ces classes lorsque des propriétés ou des méthodes renvoient des collections.»
Toutes ces interfaces héritent de IEnumerable
ce que vous devez vous assurer de comprendre. Cette interface vous permet essentiellement d'utiliser la classe dans une instruction foreach (en C #).
ICollection
est la plus élémentaire des interfaces que vous avez répertoriées. C'est une interface énumérable qui prend en charge un Count
et c'est à peu près tout.IList
est tout ce qui ICollection
est, mais il prend également en charge l'ajout et la suppression d'éléments, la récupération d'éléments par index, etc. C'est l'interface la plus couramment utilisée pour les "listes d'objets", ce qui est vague je sais.IQueryable
est une interface énumérable qui prend en charge LINQ. Vous pouvez toujours créer un IQueryable
fichier à partir d'un IList et utiliser LINQ to Objects, mais vous le trouvez également IQueryable
utilisé pour l'exécution différée d'instructions SQL dans LINQ to SQL et LINQ to Entities.IDictionary
est un animal différent dans le sens où il s'agit d'une cartographie des clés uniques aux valeurs. Il est également énumérable dans la mesure où vous pouvez énumérer les paires clé / valeur, mais sinon, il sert un objectif différent des autres que vous avez énumérésSelon MSDN, List (Of T) .Add est "une opération O (n)" (lorsque "Capacity" est dépassé) tandis que Collection (Of T) .Add est toujours "une opération O (1)". Cela serait compréhensible si List est implémenté à l'aide d'un tableau et Collection une liste liée. Cependant, si tel était le cas, on s'attendrait à ce que Collection (Of T) .Item soit "une opération O (n)". Mais - ce n'est - pas !?! Collection (Of T) .Item est "une opération O (1)" tout comme List (Of T) .Item.
En plus de cela, le message de "tuinstoel" "29 décembre 08 à 22:31" ci-dessus indique que les tests de vitesse montrent List (Of T) .Ajoutez pour être plus rapide que Collection (Of T) .Add que j'ai reproduit avec Long et String. Bien que je ne sois que 33% plus rapide que le sien revendiqué à 80%, selon MSDN, cela aurait dû être le contraire et de "n" fois!?!
Les deux implémentent les mêmes interfaces, donc ils se comportent de la même manière. Peut-être qu'ils sont mis en œuvre différemment en interne, mais cela devrait être testé.
Les seules vraies différences que je vois sont les espaces de noms et le fait qui Collection<T>
est marqué par ComVisibleAttribute(false)
, donc le code COM ne peut pas l'utiliser.
En plus d'autres réponses, j'ai compilé un aperçu rapide de la liste générique et des capacités de collecte. La collection est un sous-ensemble limité de la liste:
* = présent
o = partiellement présent
Propriété / Méthode Collection < T > Liste < T > --------------------------------------- -------
Add() * *
AddRange() *
AsReadOnly() *
BinarySearch() *
Capacity *
Clear() * *
Contains() * *
ConvertAll() *
CopyTo() o *
Count * *
Equals() * *
Exists() *
Find() *
FindAll() *
FindIndex() *
FindLast() *
FindLastIndex() *
ForEach() *
GetEnumerator() * *
GetHashCode() * *
GetRange() *
GetType() * *
IndexOf() o *
Insert() * *
InsertRange() *
Item() * *
LastIndexOf() *
New() o *
ReferenceEquals() * *
Remove() * *
RemoveAll() *
RemoveAt() * *
RemoveRange() *
Reverse() *
Sort() *
ToArray() *
ToString() * *
TrimExcess() *
TrueForAll() *