Es mejor usar Enumerable.Empty () en lugar de new List () para inicializar unerableumerable?


Supongamos que tienes una persona de clase:

public class Person
{
   public string Name { get; set;}
   public IEnumerable<Role> Roles {get; set;}
}

Obviamente debería instanciar los Roles en el constructor. Ahora, solía hacerlo con una Lista como esta :

public Person()
{
   Roles = new List<Role>();
}

Pero descubrí este método estático en el espacio de nombres System.Linq

IEnumerable<T> Enumerable.Empty<T>();

Desde MSDN:

El método Empty(TResult)() almacena en caché un secuencia vacía de tipo TResult. Cuando el objeto que devuelve se enumera, no produce elementos.

En algunos casos, este método es utilidad para pasar una secuencia vacía a una método definido por el usuario que toma un IEnumerable(T). También se puede utilizar para generar un elemento neutro para los métodos tales como Union. Ver la sección de Ejemplo para un ejemplo de este uso de

Entonces, ¿es mejor escribir el constructor así? ¿Lo usas? ¿Por qué? o si no, ¿por Qué no?

public Person()
{
   Roles = Enumerable.Empty<Role>();
}
Author: Wai Ha Lee, 2009-12-12

7 answers

Creo que la mayoría de las publicaciones pasaron por alto el punto principal. Incluso si utiliza una matriz vacía o una lista vacía, esos son objetos y se almacenan en la memoria. Que el Recolector de basura tiene que cuidar de ellos. Si se trata de una aplicación de alto rendimiento, podría ser un impacto notable.

Enumerable.Empty no crea un objeto por llamada poniendo así menos carga en GC.

Si el código está en una ubicación de bajo rendimiento, entonces se reduce a consideraciones estéticas.

 116
Author: Vadim Chekan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-08 16:55:24

Creo que Enumerable.Empty<T> es mejor porque es más explícito: su código indica claramente sus intenciones. También podría ser un poco más eficiente, pero eso es solo una ventaja secundaria.

 77
Author: Tommy Carlier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-22 08:58:22

En el frente de rendimiento, veamos cómo se implementa Enumerable.Empty<T>.

Devuelve EmptyEnumerable<T>.Instance, que se define como:

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

Los campos estáticos en tipos genéricos se asignan por parámetro de tipo genérico. Esto significa que el tiempo de ejecución puede crear perezosamente estos arrays vacíos solo para los tipos que el código de usuario necesita, y reutilizar las instancias tantas veces como sea necesario sin agregar ninguna presión al recolector de basura.

A saber:

Debug.Assert(ReferenceEquals(Enumerable.Empty<int>(), Enumerable.Empty<int>()));
 17
Author: Drew Noakes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-14 10:15:24

Suponiendo que realmente desea rellenar la propiedad Roles de alguna manera, encapsule eso haciendo que su setter sea privado e inicializándolo en una nueva lista en el constructor:

public class Person
{
    public string Name { get; set; }
    public IList<Role> Roles { get; private set; }

    public Person()
    {
        Roles = new List<Role>();
    }
}

Si realmente quieres tener el configurador público, deja Roles con un valor de null y evita la asignación de objetos.

 12
Author: Neil Barnwell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-03 17:35:48

El problema con su enfoque es que no puede agregar ningún elemento a la colección: tendría una estructura privada como list y luego expondría los elementos como Enumerables:

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 tiene la intención de que otra clase cree la lista de roles (lo cual no recomendaría), entonces no inicializaría el enumerable en Persona.

 7
Author: Lee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-12 17:18:50

El problema típico con la exposición de la Lista privada como unEnumerable es que el cliente de su clase puede meterse con ella mediante casting. Este código funcionaría:

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

Puede evitar esto implementando un iterador:

public IEnumerable<Role> Roles {
  get {
    foreach (var role in mRoles)
      yield return role;
  }
}
 6
Author: Hans Passant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-12 17:46:49

El problema más grande aquí sería exponer Roles como un campo público .

Lo siguiente se ve mejor:

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>();
        }
   }
}

Y tal vez deberías echarle un vistazo a devolverlo como una ReadOnlyCollection, dependiendo de cómo quieras usarlo.

Y Enumerable.Empty isn't better here, just a little more efficient when Roles usually stays empty.

 4
Author: Henk Holterman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-12 17:21:07