C # List .ToArray est une mauvaise performance?

J’utilise .Net 3.5 (C #) et j’ai entendu les performances de C # List.ToArray est “mauvais”, car il copie en mémoire tous les éléments pour former un nouveau tableau. Est-ce vrai?

Non ce n’est pas vrai. Les performances sont bonnes car tout ce qu’il fait est de copier en mémoire tous les éléments (*) pour former un nouveau tableau.

Bien sûr, cela dépend de ce que vous définissez comme “bonne” ou “mauvaise” performance.

(*) références pour les types de référence, valeurs pour les types de valeur.

MODIFIER

En réponse à votre commentaire, utiliser Reflector est un bon moyen de vérifier la mise en œuvre (voir ci-dessous). Ou bien réfléchissez quelques minutes à la manière de le mettre en œuvre et assurez-vous que les ingénieurs de Microsoft ne proposeront pas une solution pire.

 public T[] ToArray() { T[] destinationArray = new T[this._size]; Array.Copy(this._items, 0, destinationArray, 0, this._size); return destinationArray; } 

Bien sûr, «bonne» ou «mauvaise» performance n’a de sens que par rapport à une alternative. Si, dans votre cas spécifique, il existe une technique alternative pour atteindre votre objective qui est mesurable plus rapidement, vous pouvez alors considérer que les performances sont “mauvaises”. S’il n’y a pas d’alternative, alors la performance est “bonne” (ou “assez bonne”).

EDIT 2

En réponse au commentaire: “Pas de reconstruction d’objects?” :

Aucune reconstruction pour les types de référence. Pour les types de valeur, les valeurs sont copiées, ce qui pourrait être qualifié de reconstruction.

Raisons pour appeler ToArray ()

  • Si la valeur renvoyée n’est pas censée être modifiée, la renvoyer sous forme de tableau le rend un peu plus clair.
  • Si l’appelant est censé effectuer de nombreux access non séquentiels aux données, un tableau peut présenter un avantage en termes de performances, par rapport à une liste <>.
  • Si vous savez que vous devrez transmettre la valeur renvoyée à une fonction tierce qui attend un tableau.
  • Compatibilité avec les fonctions d’appel devant fonctionner avec .NET version 1 ou 1.1. Ces versions n’ont pas le type List <> (ni aucun type générique, d’ailleurs).

Raisons pour ne pas appeler ToArray ()

  • Si l’appelant a besoin d’append ou de supprimer des éléments, une liste <> est absolument nécessaire.
  • Les avantages en termes de performances ne sont pas nécessairement garantis, en particulier si l’appelant accède aux données de manière séquentielle. Il y a aussi l’étape supplémentaire de conversion de List <> en tableau, ce qui prend du temps de traitement.
  • L’appelant peut toujours convertir la liste en tableau.

pris d’ ici

Oui, c’est vrai qu’il fait une copie en mémoire de tous les éléments. Est-ce un problème de performance? Cela dépend de vos exigences de performance.

Une List contient un tableau interne pour contenir tous les éléments. Le tableau s’agrandit si la capacité n’est plus suffisante pour la liste. Chaque fois que cela se produit, la liste copiera tous les éléments dans un nouveau tableau. Cela arrive tout le temps, et pour la plupart des gens, ce n’est pas un problème de performances.

Par exemple, une liste avec un constructeur par défaut commence à la capacité 16, et lorsque vous .Add() le 17ème élément, il crée un nouveau tableau de taille 32, copie les 16 anciennes valeurs et ajoute le 17ème.

La différence de taille est également la raison pour laquelle ToArray() renvoie une nouvelle instance de tableau au lieu de transmettre la référence privée.

cela crée de nouvelles références dans un tableau, mais ce n’est que la seule chose que cette méthode pourrait et devrait faire …

La performance doit être comprise en termes relatifs. La conversion d’un tableau en une liste implique la copie du tableau, dont le coût dépend de la taille du tableau. Mais vous devez comparer ce coût à d’autres activités de votre programme. Comment avez-vous obtenu les informations à mettre dans le tableau en premier lieu? S’il s’agissait d’une lecture sur le disque, d’une connexion réseau ou d’une firebase database, il est très peu probable qu’une copie de masortingce en mémoire ait un impact sur le temps écoulé.

Pour tout type de liste / ICollection où il connaît la longueur, il peut allouer un tableau de la taille exacte dès le début.

 T[] destinationArray = new T[this._size]; Array.Copy(this._items, 0, destinationArray, 0, this._size); return destinationArray; 

Si votre type de source est IEnumerable (pas une liste / collection), alors la source est:

 items = new TElement[4]; .. if (no more space) { TElement[] newItems = new TElement[checked(count * 2)]; Array.Copy(items, 0, newItems, 0, count); items = newItems; 

Il commence à la taille 4 et croît de manière exponentielle en doublant chaque fois qu’il manque d’espace. Chaque fois qu’il double, il doit réaffecter la mémoire et copier les données.

Si nous connaissons la taille des données source, nous pouvons éviter cette légère surcharge. Cependant, dans la plupart des cas, par exemple, la taille d’un tableau <= 1024 sera exécutée si rapidement que nous n'aurons même pas besoin de penser à ces détails d'implémentation.

Références: Enumerable.cs, List.cs (F12ing into eux), la réponse de Joe