是否更好地使用Enumerable.Empty <t>()而不是新的List <t>()来初始化IEnumerable <t>?</t> </t> </t>

时间:2009-12-12 17:05:57

标签: c# linq constructor

假设你有一个人类:

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

我显然应该在构造函数中实例化角色。 现在,我曾经使用像这样的List:

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

但是我在System.Linq命名空间

中发现了这个静态方法
IEnumerable<T> Enumerable.Empty<T>();

来自MSDN

  

Empty(TResult)()方法缓存了一个   TResult类型的空序列。什么时候   它返回的对象是枚举的,   它没有产生任何元素。

     

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

的使用示例

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

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

7 个答案:

答案 0 :(得分:137)

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

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

如果代码处于低吞吐量位置,那么它可归结为审美考虑因素。

答案 1 :(得分:83)

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

答案 2 :(得分:19)

在效果方面,让我们看看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>()));

答案 3 :(得分:12)

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

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

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

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

答案 4 :(得分:7)

您的方法存在的问题是您无法向集合中添加任何项目 - 我将拥有类似列表的私有结构,然后将这些项目公开为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(); }
    }
}

如果你打算让其他一些类创建角色列表(我不推荐),那么我就不会在Person中初始化可枚举。

答案 5 :(得分:6)

将私有List作为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;
  }
}

答案 6 :(得分:4)

此处较大的问题是将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,当角色通常保持空白时效率会更高一些。

相关问题