Est-il préférable d’utiliser Enumerable.Empty () par opposition à la nouvelle List () pour initialiser un IEnumerable ?

Supposons que vous ayez une personne de classe:

public class Person { public ssortingng Name { get; set;} public IEnumerable Roles {get; set;} } 

Je devrais évidemment instancier les rôles dans le constructeur. Maintenant, je le faisais avec une liste comme celle-ci:

 public Person() { Roles = new List(); } 

Mais j’ai découvert cette méthode statique dans l’espace de noms System.Linq

 IEnumerable Enumerable.Empty(); 

De MSDN :

La méthode Empty(TResult)() met en cache une séquence vide de type TResult . Lorsque l’object renvoyé est énuméré, il ne génère aucun élément.

Dans certains cas, cette méthode est utile pour transmettre une séquence vide à une méthode définie par l’utilisateur qui prend un IEnumerable(T) . Il peut également être utilisé pour générer un élément neutre pour des méthodes telles que Union . Voir la section Exemple pour un exemple de cette utilisation de

Alors, vaut-il mieux écrire le constructeur comme ça? L’utilisez vous? Pourquoi? ou sinon, pourquoi pas?

 public Person() { Roles = Enumerable.Empty(); } 

Je pense que la plupart des offres ont manqué le point principal. Même si vous utilisez un tableau vide ou une liste vide, il s’agit d’objects et ils sont stockés en mémoire. Que le ramasse-miettes doit en prendre soin. Si vous avez affaire à une application à haut débit, cela pourrait avoir un impact notable.

Enumerable.Empty ne crée pas d’object par appel, ce qui place moins de charge sur le GC.

Si le code est à faible débit, cela se résume à des considérations esthétiques.

Je pense que Enumerable.Empty est préférable car il est plus explicite: votre code indique clairement vos intentions. Cela pourrait aussi être un peu plus efficace, mais ce n’est qu’un avantage secondaire.

Sur le front des performances, voyons comment Enumerable.Empty est implémenté.

Il renvoie EmptyEnumerable.Instance , qui est défini comme suit:

 internal class EmptyEnumerable { public static readonly T[] Instance = new T[0]; } 

Les champs statiques sur les types génériques sont alloués par paramètre de type générique. Cela signifie que le moteur d’exécution peut créer ces tableaux vides uniquement pour les types de code utilisateur requirejs et réutiliser les instances autant de fois que nécessaire sans append de pression sur le récupérateur de mémoire.

En être témoin:

 Debug.Assert(ReferenceEquals(Enumerable.Empty(), Enumerable.Empty())); 

En supposant que vous vouliez en fait remplir la propriété Roles manière ou d’une autre, encapsulez cela en rendant son setter privé et en l’initialisant à une nouvelle liste dans le constructeur:

 public class Person { public ssortingng Name { get; set; } public IList Roles { get; private set; } public Person() { Roles = new List(); } } 

Si vous voulez vraiment avoir le composeur public, laissez Roles avec une valeur null et évitez l’allocation d’object.

Le problème avec votre approche est que vous ne pouvez pas append d’éléments à la collection – j’aurais une structure de type structure privée, puis exposerais les éléments en tant qu’Enumerable:

 public class Person { private IList _roles; public Person() { this._roles = new List(); } public ssortingng Name { get; set; } public void AddRole(Role role) { //implementation } public IEnumerable Roles { get { return this._roles.AsEnumerable(); } } } 

Si vous avez l’intention de créer une liste de rôles avec d’autres classes (que je ne recommanderais pas), alors je ne voudrais pas initialiser l’innombrable en personne.

Le problème typique lié à l’exposition de la liste privée en tant que IEnumerable est que le client de votre classe peut le gâcher en le diffusant. Ce code fonctionnerait:

  var p = new Person(); List roles = p.Roles as List; roles.Add(Role.Admin); 

Vous pouvez éviter cela en implémentant un iterator:

 public IEnumerable Roles { get { foreach (var role in mRoles) yield return role; } } 

Le plus gros problème ici serait d’exposer les Roles tant que domaine public .

les éléments suivants semblent meilleurs:

 public class Person { public ssortingng Name { get; set; } private List _roles = null; public IEnumerable Roles { get { if (_roles != null) return _roles; else return Enumerable.Empty(); } } } 

Et peut-être devriez-vous envisager de le retourner en tant que ReadonlyCollection , en fonction de la manière dont vous souhaitez l’utiliser.

Et Enumerable.Empty n’est pas better ici, juste un peu plus efficace lorsque les rôles restnt généralement vides.