由于 - IList<>而避免不必要的列表创建.ToList()

时间:2014-01-05 12:49:17

标签: c#

我找到了.ToList()的更多代码,其中需要对IList<t>方法调用结果进行列表操作。
因此,当返回IList<t>的方法在内部使用List作为实例时,在使用ToList()之前进行某种形式的检查似乎是合适的。

ToList扩展程序似乎无法检查源是否已经是List。 请参阅下面的反编译源。

是一个自定义扩展,以避免看起来像列表重复一个好主意? 例如

public  static List<T> ToListWCheck<T>(this IEnumerable<T> source) {
   if (source == null){ return null;}               
   var isListAlready = source as List<T>;
   return isListAlready ?? source.ToList();
}

有没有更好的方法来处理IList&lt;&gt;列出&lt;&gt;有效;吗

// Extract from System.Linq.Enumerable

 public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
 {
  if (source == null)
    throw Error.ArgumentNull("source");
  else
    return new List<TSource>(source);
}
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Collections.Generic.List`1"/> class that contains elements copied from the specified collection and has sufficient capacity to accommodate the number of elements copied.
/// </summary>
/// <param name="collection">The collection whose elements are copied to the new list.</param><exception cref="T:System.ArgumentNullException"><paramref name="collection"/> is null.</exception>
[__DynamicallyInvokable]
public List(IEnumerable<T> collection)
{
  if (collection == null)
    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
  ICollection<T> collection1 = collection as ICollection<T>;
  if (collection1 != null)
  {
    int count = collection1.Count;
    if (count == 0)
    {
      this._items = List<T>._emptyArray;
    }
    else
    {
      this._items = new T[count];
      collection1.CopyTo(this._items, 0);
      this._size = count;
    }
  }
  else
  {
    this._size = 0;
    this._items = List<T>._emptyArray;
    foreach (T obj in collection)
      this.Add(obj);
  }
}

2 个答案:

答案 0 :(得分:2)

对于那些可能不知道的人,从.NET 4.5开始添加了IReadOnlyList<T>。当我知道我创建列表一次并且不打算再次更改它时,我已经开始使用此代替IEnumerable<T>作为返回值。如果沿着调用链一致地使用它,则可以避免在整个地方创建多个列表副本。实际上,我的一个应用程序在列表上执行了大量操作,从而显着提高了性能。

对于更强大的保证,新的Immutable Collections包中有ImmutableList<T>,它不是框架的严格组成部分,但是作为Microsoft的官方扩展版本发布。在这个和上面之间,我认为我们会看到在任何地方使用IEnumerable的速度都很慢。我认为这是一件好事,因为以前很难判断一个方法是否使用了延迟执行,这意味着你经常会立即调用ToList()或ToArray(),在函数创建时创建不必要的副本,在内部返回一个集合。

答案 1 :(得分:1)

将一些评论(我和其他人)转变为可行的答案......

如果有诱惑要覆盖.ToList()本身,绝对不要这样做。 .ToList()的功能是枚举枚举并创建它的内存列表。如果该枚举已经一个列表,则无关紧要。使它重要将打破可枚举的抽象。更不用说创建一个{em>有时返回新列表的.ToList()方法,有时返回对原始源的引用肯定引入副作用。微妙,难以调试的副作用。

在创建一个单独的方法方面,它肯定是可行的,但我会谨慎行事。我同意@bas发布的评论,它更多的是代码味道而不是其他任何东西。如果您在IList<T>上创建这样的方法,那么它就是多余的。如果你在IEnumerable<T>上创建它,那么你又会创建一些有时做一件事而有时做另一件事的事情,这巧妙地打破了抽象。

可以创建此方法,但我会非常小心该方法的名称和intellisense文档。清楚地宣传非常它的作用。方法名称绝不应该是错误信息。但也要问问自己,潜在的性能增益是否超过抽象的微妙损失和实现的微妙耦合。我怀疑它没有。并且您不希望发现自己处于这样一种位置:在整个代码库中只使用然后来发现它的效果并不像希望的那样好,因为还原所有这些用途反过来也会产生副作用和错误。

你能做到吗?是。你应该?这可能没有必要。