MyClass[] array;
List<MyClass> list;
Quels sont les scénarios où l'un est préférable à l'autre? Et pourquoi?
MyClass[] array;
List<MyClass> list;
Quels sont les scénarios où l'un est préférable à l'autre? Et pourquoi?
Réponses:
Il est rare, en réalité, que vous souhaitiez utiliser un tableau. Utilisez List<T>
certainement n'importe quand vous souhaitez ajouter / supprimer des données, car le redimensionnement des tableaux est coûteux. Si vous savez que les données sont de longueur fixe et que vous souhaitez micro-optimiser pour une raison très spécifique (après l'analyse comparative), un tableau peut être utile.
List<T>
offre beaucoup plus de fonctionnalités qu'un tableau (bien que LINQ égalise un peu), et est presque toujours le bon choix. Sauf pour les params
arguments, bien sûr. ;-p
En tant que compteur - List<T>
est unidimensionnel; où-comme vous avez des tableaux rectangulaires (etc) comme int[,]
ou string[,,]
- mais il existe d'autres façons de modéliser ces données (si vous en avez besoin) dans un modèle d'objet.
Voir également:
Cela dit, j'utilise beaucoup les tableaux dans mon projet protobuf-net ; entièrement pour la performance:
byte[]
est à peu près essentiel pour l'encodage;byte[]
tampon de roulement local que je remplis avant de l'envoyer vers le flux sous-jacent (et vv); plus rapide que BufferedStream
etc;Foo[]
plutôt que List<Foo>
), car la taille est fixe une fois construite et doit être très rapide.Mais c'est définitivement une exception; pour le traitement général du secteur d'activité, un List<T>
gagne à chaque fois.
Vraiment juste répondre pour ajouter un lien qui me surprend n'a pas encore été mentionné: l'entrée de blog d'Eric Lippert sur "Les tableaux sont considérés comme quelque peu nocifs".
Vous pouvez juger du titre qu'il suggère d'utiliser des collections partout où cela est pratique - mais comme Marc le fait remarquer à juste titre, il existe de nombreux endroits où un tableau est vraiment la seule solution pratique.
Nonobstant les autres réponses recommandées List<T>
, vous voudrez utiliser des tableaux lors de la manipulation:
List<T>
d'un tableau ici plutôt que d'un tableau d'octets?
Sauf si vous êtes vraiment préoccupé par les performances, et par là je veux dire, "Pourquoi utilisez-vous .Net au lieu de C ++?" vous devriez vous en tenir à Liste <>. Il est plus facile à entretenir et fait tout le sale boulot de redimensionner un tableau en arrière-plan pour vous. (Si nécessaire, List <> est assez intelligent pour choisir les tailles de tableau, il n'est donc pas nécessaire de le faire habituellement.)
Les tableaux doivent être utilisés de préférence à List lorsque l'immuabilité de la collection elle-même fait partie du contrat entre le code client et fournisseur (pas nécessairement l'immuabilité des éléments de la collection) ET lorsque IEnumerable ne convient pas.
Par exemple,
var str = "This is a string";
var strChars = str.ToCharArray(); // returns array
Il est clair que la modification de "strChars" ne mutera pas l'objet "str" d'origine, quelle que soit la connaissance au niveau de l'implémentation du type sous-jacent de "str".
Mais supposons que
var str = "This is a string";
var strChars = str.ToCharList(); // returns List<char>
strChars.Insert(0, 'X');
Dans ce cas, il n'est pas clair à partir de cet extrait de code seul si la méthode d'insertion mutera ou non l'objet "str" d'origine. Il faut une connaissance de String de la mise en œuvre pour faire cette détermination, ce qui rompt l'approche Design by Contract. Dans le cas de String, ce n'est pas un gros problème, mais cela peut être un gros problème dans presque tous les autres cas. La définition de la liste en lecture seule aide mais entraîne des erreurs d'exécution, pas de compilation.
To
va créer un objet qui n'a pas la capacité de modifier l'instance d'origine, contrairement à strChars as char[]
ce qui, s'il est valide, suggérerait que vous êtes maintenant en mesure de modifier l'objet d'origine.
str
interne utilise un tableau et ToCharArray
renvoie une référence à ce tableau, le client peut muter str
en modifiant les éléments de ce tableau, même si la taille reste fixe. Pourtant, vous écrivez «Il est clair que la modification de« strChars »ne mutera pas l'objet« str »d'origine». Qu'est-ce que j'oublie ici? D'après ce que je peux voir, dans les deux cas, le client peut avoir accès à la représentation interne et, quel que soit le type, cela permettrait une mutation quelconque.
Si je sais exactement combien d'éléments que je vais avoir besoin, dire que je besoin de 5 éléments et que jamais 5 éléments puis - je utiliser un tableau. Sinon, j'utilise simplement une liste <T>.
La plupart du temps, utiliser un List
suffirait. A List
utilise un tableau interne pour gérer ses données et redimensionne automatiquement le tableau lors de l'ajout de plus d'éléments à List
sa capacité actuelle, ce qui le rend plus facile à utiliser qu'un tableau, où vous devez connaître la capacité au préalable.
Voir http://msdn.microsoft.com/en-us/library/ms379570(v=vs.80).aspx#datastructures20_1_topic5 pour plus d'informations sur les listes en C # ou simplement décompiler System.Collections.Generic.List<T>
.
Si vous avez besoin de données multidimensionnelles (par exemple en utilisant une matrice ou en programmation graphique), vous iriez probablement avec un à la array
place.
Comme toujours, si la mémoire ou les performances sont un problème, mesurez-le! Sinon, vous pourriez faire de fausses hypothèses sur le code.
Arrays Vs. Les listes sont un problème classique de maintenabilité par rapport aux performances. La règle générale que presque tous les développeurs suivent est que vous devez viser les deux, mais lorsqu'ils entrent en conflit, choisissez la maintenabilité plutôt que les performances. L'exception à cette règle est lorsque les performances se sont déjà révélées être un problème. Si vous portez ce principe dans Arrays Vs. Listes, alors ce que vous obtenez est le suivant:
Utilisez des listes fortement typées jusqu'à ce que vous rencontriez des problèmes de performances. Si vous rencontrez un problème de performances, décidez si le décrochage vers les baies bénéficiera davantage à votre solution en termes de performances qu’au détriment de votre solution en termes de maintenance.
Une autre situation non encore mentionnée est celle où l'on aura un grand nombre d'éléments, dont chacun se compose d'un tas fixe de variables liées mais indépendantes collées ensemble (par exemple les coordonnées d'un point ou les sommets d'un triangle 3D). Un tableau de structures de champ exposé permettra à ses éléments d'être efficacement modifiés "en place" - ce qui n'est pas possible avec tout autre type de collection. Parce qu'un tableau de structures contient ses éléments consécutivement dans la RAM, les accès séquentiels aux éléments du tableau peuvent être très rapides. Dans les situations où le code devra effectuer de nombreux passages séquentiels à travers un tableau, un tableau de structures peut surpasser un tableau ou une autre collection de références d'objet de classe d'un facteur 2: 1; plus loin,
Bien que les tableaux ne soient pas redimensionnables, il n'est pas difficile de faire en sorte que le code stocke une référence de tableau avec le nombre d'éléments utilisés et remplace le tableau par un plus grand si nécessaire. Alternativement, on pourrait facilement écrire du code pour un type qui se comportait un peu comme un List<T>
mais exposait sa mémoire de sauvegarde, permettant ainsi de dire soit MyPoints.Add(nextPoint);
ou MyPoints.Items[23].X += 5;
. Notez que ce dernier ne lèverait pas nécessairement une exception si le code tentait d'accéder au-delà de la fin de la liste, mais l'utilisation serait sinon conceptuellement assez similaire à List<T>
.
Point[] arr;
, il est possible pour le code de dire, par exemple arr[3].x+=q;
. En utilisant par exemple List<Point> list
, il faudrait plutôt dire Point temp=list[3]; temp.x+=q; list[3]=temp;
. Il serait utile d' List<T>
avoir une méthode Update<TP>(int index, ActionByRefRef<T,TP> proc, ref TP params)
. et les compilateurs pourraient se transformer list[3].x+=q;
en{list.Update(3, (ref int value, ref int param)=>value+=param, ref q);
mais aucune telle fonctionnalité n'existe.
list[0].X += 3;
ajoutera 3 à la propriété X du premier élément de la liste. Et list
est une List<Point>
et Point
est une classe avec des propriétés X et Y
Les listes dans .NET sont des wrappers sur des tableaux et utilisent un tableau en interne. La complexité temporelle des opérations sur les listes est la même que pour les tableaux, mais il y a un peu plus de surcharge avec toutes les fonctionnalités / facilité d'utilisation des listes (telles que le redimensionnement automatique et les méthodes fournies avec la classe de liste). À peu près, je recommanderais d'utiliser des listes dans tous les cas, sauf s'il existe une raison impérieuse de ne pas le faire, comme si vous avez besoin d'écrire du code extrêmement optimisé ou si vous travaillez avec un autre code construit autour de tableaux.
Plutôt que de passer par une comparaison des fonctionnalités de chaque type de données, je pense que la réponse la plus pragmatique est "les différences ne sont probablement pas si importantes pour ce que vous devez accomplir, d'autant plus qu'elles implémentent toutes les deux IEnumerable
, alors suivez la convention populaire et utilisez un List
jusqu'à ce que vous ayez une raison de ne pas le faire, auquel cas vous aurez probablement votre raison d'utiliser un tableau sur un List
".
La plupart du temps, dans le code managé, vous souhaiterez privilégier les collections avec autant de facilité de travail que de vous soucier des micro-optimisations.
Ils peuvent être impopulaires, mais je suis un fan d'Arrays dans les projets de jeux. - La vitesse d'itération peut être importante dans certains cas, car chaque sur un tableau a beaucoup moins de frais généraux si vous ne faites pas beaucoup par élément - L'ajout et la suppression ne sont pas si difficiles avec les fonctions d'assistance - C'est plus lent, mais dans les cas où vous ne le construisez qu'une seule fois cela peut ne pas avoir d'importance - Dans la plupart des cas, moins de mémoire supplémentaire est gaspillée (seulement vraiment significative avec les tableaux de structures) - Légèrement moins de déchets et de pointeurs et de chasse aux pointeurs
Cela étant dit, j'utilise List beaucoup plus souvent que Arrays dans la pratique, mais ils ont chacun leur place.
Ce serait bien si List où un type intégré afin qu'ils puissent optimiser l'encapsulage et les frais généraux d'énumération.
Remplir une liste est plus facile qu'un tableau. Pour les tableaux, vous devez connaître la longueur exacte des données, mais pour les listes, la taille des données peut être quelconque. Et, vous pouvez convertir une liste en tableau.
List<URLDTO> urls = new List<URLDTO>();
urls.Add(new URLDTO() {
key = "wiki",
url = "https://...",
});
urls.Add(new URLDTO()
{
key = "url",
url = "http://...",
});
urls.Add(new URLDTO()
{
key = "dir",
url = "https://...",
});
// convert a list into an array: URLDTO[]
return urls.ToArray();
Puisque personne ne mentionne: En C #, un tableau est une liste. MyClass[]
et les List<MyClass>
deux implémentent IList<MyClass>
. (par exemple void Foo(IList<int> foo)
peut être appelé comme Foo(new[] { 1, 2, 3 })
ouFoo(new List<int> { 1, 2, 3 })
)
Donc, si vous écrivez une méthode qui accepte un List<MyClass>
comme argument, mais n'utilise qu'un sous-ensemble de fonctionnalités, vous pouvez déclarer commeIList<MyClass>
place pour la commodité des appelants.
Détails:
List
, il implémente uniquement l' IList
interface.
Cela dépend complètement des contextes dans lesquels la structure de données est nécessaire. Par exemple, si vous créez des éléments à utiliser par d'autres fonctions ou services, List est le moyen idéal pour y parvenir.
Maintenant, si vous avez une liste d'éléments et que vous souhaitez simplement les afficher, disons que sur un tableau de pages Web est le conteneur que vous devez utiliser.
IEnumerable<T>
- alors je peux diffuser des objets plutôt que de les mettre en mémoire tampon.
Il convient de mentionner la possibilité de lancer sur place.
interface IWork { }
class Foo : IWork { }
void Test( )
{
List<Foo> bb = new List<Foo>( );
// Error: CS0029 Cannot implicitly convert type 'System.Collections.Generic.List<Foo>' to 'System.Collections.Generic.List<IWork>'
List<IWork> cc = bb;
Foo[] bbb = new Foo[4];
// Fine
IWork[] ccc = bbb;
}
Ainsi, Array offre un peu plus de flexibilité lorsqu'il est utilisé dans le type de retour ou l'argument pour les fonctions.
IWork[] GetAllWorks( )
{
List<Foo> fooWorks = new List<Foo>( );
return fooWorks.ToArray( ); // Fine
}
void ExecuteWorks( IWork[] works ) { } // Also accept Foo[]