C# 与 new List<T>() 相比,使用 Enumerable.Empty<T>() 来初始化 IEnumerable<T> 是否更好?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1894038/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 21:41:38  来源:igfitidea点击:

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

c#linqconstructor

提问by Stéphane

Suppose you have a class Person :

假设你有一个类 Person :

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

I should obviously instantiate the Roles in the constructor. Now, I used to do it with a List like this :

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

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

But I discovered this static method in the System.Linqnamespace

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

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

From MSDN:

MSDN

The Empty(TResult)()method caches an empty sequence of type TResult. When the object it returns is enumerated, it yields no elements.

In some cases, this method is useful for passing an empty sequence to a user-defined method that takes an IEnumerable(T). It can also be used to generate a neutral element for methods such as Union. See the Example section for an example of this use of

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

在某些情况下,此方法可用于将空序列传递给采用 IEnumerable(T). 它还可用于为诸如Union. 有关此用法的示例,请参阅示例部分

So is it better to write the constructor like that? Do you use it? Why? or if not, Why not?

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

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

采纳答案by Vadym Chekan

I think most postings missed the main point. Even if you use empty array or empty list, those are objects and they are stored in memory. Than Garbage Collector has to take care of them. If you are dealing with high throughput application, it could be noticeable impact.

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

Enumerable.Emptydoes not create an object per call thus putting less load on GC.

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

If the code is in low-throughput location, then it boils down to aesthetic considerations though.

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

回答by Tommy Carlier

I think Enumerable.Empty<T>is better because it is more explicit: your code clearly indicates your intentions. It might also be a bit more efficient, but that's only a secondary advantage.

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

回答by Henk Holterman

The larger problem here would be exposing Rolesas a public field.

这里更大的问题是Roles作为公共领域公开

the following looks better:

以下看起来更好:

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

And maybe you should take a look at returning it as a ReadonlyCollection, depending on how you want to use it.

也许您应该考虑将其作为ReadonlyCollection返回,具体取决于您想如何使用它。

And Enumerable.Empty isn't betterhere, just a little more efficient when Roles usually stays empty.

而 Enumerable.Empty 不在better这里,只是当 Roles 通常保持为空时效率会更高一些。

回答by Lee

The problem with your approach is that you can't add any items to the collection - I would have a private structure like list and then expose the items as an Enumerable:

你的方法的问题是你不能向集合中添加任何项目 - 我会有一个像 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(); }
    }
}

If you intend some other class to create the list of roles (which I wouldn't recommend) then I wouldn't initialise the enumerable at all in Person.

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

回答by Neil Barnwell

Assuming you actually want to populate the Rolesproperty somehow, then encapsulate that by making it's setter private and initialising it to a new list in the constructor:

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

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

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

If you really really want to have the public setter, leave Roleswith a value of nulland avoid the object allocation.

如果你真的想拥有公共设置器,请保留Roles一个值null并避免对象分配。

回答by Hans Passant

The typical problem with exposing the private List as an IEnumerable is that the client of your class can mess with it by casting. This code would work:

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

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

You can avoid this by implementing an iterator:

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

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

回答by Drew Noakes

On the performance front, let's see how Enumerable.Empty<T>is implemented.

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

It returns EmptyEnumerable<T>.Instance, which is defined as:

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

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

Static fields on generic types are allocated per generic type parameter. This means that the runtime can lazily create these empty arrays only for the types user code needs, and reuse the instances as many times as needed without adding any pressure on the garbage collector.

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

To wit:

以机智:

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