Supposons que vous ayez une personne de classe:
public class Person
{
public string Name { get; set;}
public IEnumerable<Role> 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<Role>();
}
Mais j'ai découvert cette méthode statique dans l'espace de noms System.Linq
IEnumerable<T> Enumerable.Empty<T>();
De MSDN :
La méthode
Empty(TResult)()
met en cache une séquence vide de typeTResult
. Lorsque l'objet qu'il renvoie est énuméré, il ne donne aucun élément.Dans certains cas, cette méthode est utile pour passer une séquence vide à une méthode définie par l'utilisateur qui prend une
IEnumerable(T)
. Il peut également être utilisé pour générer un élément neutre pour des méthodes telles queUnion
. 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<Role>();
}
Je pense que la plupart des messages ont manqué le point principal. Même si vous utilisez un tableau vide ou une liste vide, ce sont des objets et ils sont stockés en mémoire. Than Garbage Collector doit s'en occuper. Si vous avez affaire à une application à haut débit, cela pourrait avoir un impact notable.
Enumerable.Empty
ne crée pas d'objet par appel mettant ainsi moins de charge sur GC.
Si le code se trouve dans un emplacement à faible débit, il se résume cependant à des considérations esthétiques.
Je pense Enumerable.Empty<T>
c'est mieux car c'est plus explicite: votre code indique clairement vos intentions. Il pourrait également être un peu plus efficace, mais ce n'est qu'un avantage secondaire.
Sur le plan des performances, voyons comment Enumerable.Empty<T>
est implémenté.
Il renvoie EmptyEnumerable<T>.Instance
, qui est défini comme:
internal class EmptyEnumerable<T>
{
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 l'environnement d'exécution peut paresseusement créer ces tableaux vides uniquement pour les types de code utilisateur requis et réutiliser les instances autant de fois que nécessaire sans ajouter de pression sur le garbage collector.
En être témoin:
Debug.Assert(ReferenceEquals(Enumerable.Empty<int>(), Enumerable.Empty<int>()));
En supposant que vous vouliez réellement remplir la propriété Roles
d'une manière ou d'une autre, puis encapsulez cela en rendant son setter privé et en l'initialisant dans une nouvelle liste dans le constructeur:
public class Person
{
public string Name { get; set; }
public IList<Role> Roles { get; private set; }
public Person()
{
Roles = new List<Role>();
}
}
Si vous voulez vraiment vraiment avoir le setter public, laissez Roles
avec une valeur de null
et évitez l'allocation d'objet.
Le problème avec votre approche est que vous ne pouvez pas ajouter d'éléments à la collection - j'aurais une structure privée comme une liste, puis exposerais les éléments en tant qu'énumérables:
public class Person
{
private IList<Role> _roles;
public Person()
{
this._roles = new List<Role>();
}
public string Name { get; set; }
public void AddRole(Role role)
{
//implementation
}
public IEnumerable<Role> Roles
{
get { return this._roles.AsEnumerable(); }
}
}
Si vous avez l'intention qu'une autre classe crée la liste des rôles (que je ne recommanderais pas), je n'initialiserais pas du tout l'énumérable dans Person.
Le problème typique avec l'exposition de la liste privée en tant qu'IEnumerable est que le client de votre classe peut jouer avec elle en transtypant. Ce code fonctionnerait:
var p = new Person();
List<Role> roles = p.Roles as List<Role>;
roles.Add(Role.Admin);
Vous pouvez éviter cela en implémentant un itérateur:
public IEnumerable<Role> Roles {
get {
foreach (var role in mRoles)
yield return role;
}
}
Le plus gros problème ici serait d'exposer Roles
comme un champ public .
ce qui suit ressemble mieux:
public class Person
{
public string Name { get; set; }
private List<Role> _roles = null;
public IEnumerable<Role> Roles
{
get {
if (_roles != null)
return _roles;
else
return Enumerable.Empty<Role>();
}
}
}
Et peut-être devriez-vous jeter un coup d'œil au retour en tant que ReadonlyCollection , selon la façon dont vous souhaitez l'utiliser.
Et Enumerable.Empty n'est pas better
ici, juste un peu plus efficace lorsque les rôles restent généralement vides.