繁体   English   中英

使用 Enumerable.Empty 是否更好<T> () 而不是 new List<T> () 初始化一个 IEnumerable<T> ?

[英]Is it better to use Enumerable.Empty<T>() as opposed to new List<T>() to initialize an IEnumerable<T>?

假设你有一个类 Person :

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

我显然应该在构造函数中实例化角色。 现在,我曾经用这样的列表来做:

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

但是我在System.Linq命名空间中发现了这个静态方法

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

MSDN

Empty(TResult)()方法缓存TResult类型的空序列。 当枚举它返回的对象时,它不会产生任何元素。

在某些情况下,此方法可用于将空序列传递给采用IEnumerable(T)的用户定义方法。 它还可用于为诸如Union方法生成中性元素。 有关此用法的示例,请参阅示例部分

那么这样编写构造函数会更好吗? 你使用它吗? 为什么? 如果没有,为什么不呢?

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

我认为大多数帖子都没有抓住要点。 即使您使用空数组或空列表,它们也是对象并且它们存储在内存中。 垃圾收集器必须照顾它们。 如果您正在处理高吞吐量应用程序,这可能会产生明显的影响。

Enumerable.Empty不会在每次调用时创建一个对象,从而减少了 GC 的负载。

如果代码位于低吞吐量位置,那么它归结为美学考虑。

我认为Enumerable.Empty<T>更好,因为它更明确:您的代码清楚地表明了您的意图。 它也可能更有效率,但这只是次要优势。

在性能方面,让我们看看Enumerable.Empty<T>是如何实现的。

它返回EmptyEnumerable<T>.Instance ,其定义为:

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

泛型类型的静态字段按泛型类型参数分配。 这意味着运行时可以只为用户代码需要的类型懒惰地创建这些空数组,并根据需要多次重用实例,而不会给垃圾收集器增加任何压力。

以机智:

Debug.Assert(ReferenceEquals(Enumerable.Empty<int>(), Enumerable.Empty<int>()));

假设您确实想以某种方式填充Roles属性,然后通过将其设置为私有并将其初始化为构造函数中的新列表来封装它:

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

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

如果您真的想要公共设置器,请将Roles的值保留为null并避免对象分配。

你的方法的问题是你不能向集合中添加任何项目 - 我会有一个像 list 这样的私有结构,然后将这些项目公开为一个 Enumerable:

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

如果您打算使用其他类来创建角色列表(我不建议这样做),那么我根本不会亲自初始化可枚举项。

将私有列表公开为 IEnumerable 的典型问题是您的类的客户端可能会通过强制转换来弄乱它。 这段代码可以工作:

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

您可以通过实现迭代器来避免这种情况:

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

这里更大的问题是将Roles暴露为公共领域

以下看起来更好:

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

也许您应该看一下将其作为ReadonlyCollection返回,具体取决于您希望如何使用它。

并且Enumerable.Empty在这里并不是better ,当角色通常保持空置时效率更高一些。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM