【问题标题】:Why refactor argument of List<Term> to IEnumerable<Term>?为什么要将 List<Term> 的参数重构为 IEnumerable<Term>?
【发布时间】:2011-12-14 00:03:05
【问题描述】:

我有一个看起来像这样的方法:

    public void UpdateTermInfo(List<Term> termInfoList)
    {
        foreach (Term termInfo in termInfoList)
        {
            UpdateTermInfo(termInfo);
        }
        m_xdoc.Save(FileName.FullName);
    }

Resharper 建议我将方法签名更改为 IEnumerable&lt;Term&gt; 而不是 List&lt;Term&gt;。这样做有什么好处?

【问题讨论】:

  • @cherhan 有点相反,但我想优点/缺点是一样的
  • R# 6 有“为什么 ReSharper 建议这样做?”灯泡菜单上的项目,它将带您to JetBrains' explanation。请注意,R# 并不是“建议”您做任何事情,只是指出该参数 可以 键入为 IEnumerable&lt;&gt;
  • 投票重新开放。重复的问题有适用于这个问题的答案,但重点不同。由于焦点的改变,这个问题的答案提供了更多有用的信息。
  • @Brian Fine,我会翻牌的。 :-P

标签: c# interface refactoring resharper


【解决方案1】:

其他答案指出,通过选择“较大”类型,您可以允许更广泛的呼叫者给您打电话。这本身就是做出这种改变的充分理由。但是,还有其他原因。我建议您进行此更改,因为当我看到一个采用列表或数组的方法时,我首先想到的是“如果该方法试图更改我的列表/数组中的项目怎么办?”

您需要存储桶的内容,但您不仅需要存储桶,还需要更改其内容的能力。如果您不打算使用该能力,为什么会要求这样做?当您说“此方法不能采用任何旧序列;它必须采用由整数索引的可变列表”时,我认为您对调用者提出了该要求因为您重新利用这种力量

如果“我打算弄乱你的数据结构”不是你打算与方法的调用者交流的内容,那么不要交流。采用序列的方法传达“我要做的最多就是从这个序列中按顺序读取”。

【讨论】:

  • 切换到IEnumerable&lt;T&gt; 会产生一个新问题:现在枚举多次可能会出现问题。虽然在此特定示例中并非如此,但在其他一些情况下可能会使选择变得更加困难。
  • 我不确定我是否理解枚举 IEnumerable 与枚举 List 相比有什么问题。
  • @GregD:因为当您列举一个列表时,您可以简单地说“给我第一项、第二项、第三项、第四项,现在我又想要第二项”。要对任意序列执行相同操作,您必须重新开始整个事情,这可能会产生巨大的性能成本。如果您需要做这种事情,可能正确的做法是尝试将 IE 强制转换为 IList,或者对 IE 执行 ToList 以将其转换为列表形式.
  • 啊,我想我对枚举的个人定义意味着列表的有序演练。如果我再次想要第二项,我认为除枚举之外的操作(当然)支持随机访问而不是有序访问的操作更合适。我读了 CodeInChaos 的评论,认为 foreach(T t in myEnum) 在某种程度上比 foreach(T t in myList) 更繁重。如果引用 Count vs Count() 会更有意义。
  • @BenjaminPodszun:想象一下在多种方法中这样做,然后在大列表中调用它们。您必须为这些方法中的每一个创建这个大列表的副本;如果您接受了List&lt;T&gt;(或ICollection&lt;T&gt;T[]),您就不必创建副本,而且您的代码在时间和内存上都会更有效。
【解决方案2】:

简单地说,接受可枚举允许您的函数与更广泛的输入参数(例如数组和 LINQ 查询)兼容。

要解释接受 LINQ 查询,可以这样做:

UpdateTermInfo(myTermList.Where(x => somefilter));

此外,指定接口而不是具体类允许其他人提供他们自己的该接口实现。通过这种方式,你是在“订阅”而不是“禁止”。 (是的,我只是编了一个词。)

一般而言(与您希望为以后可能的修改保留何种能力有关的许多例外情况),使用最通用的参数来实现函数是最佳实践。这为函数的使用者提供了最大的灵活性。

因此,如果您对使用该函数的列表一无所知(可能是因为在以后的某个日期您可能希望使用诸如Count 或索引运算符之类的属性),我强烈敦促出于上述原因,您可以考虑使用IList&lt;Term&gt; 而不是List&lt;Term&gt;

【讨论】:

  • 不能对列表使用 LINQ 查询吗?
  • @ThePower David 表明 input 可以是 LINQ 过滤器... 不是 List&lt;T&gt;
  • @ThePower 你当然可以,但是这样的查询的结果将是一个可枚举的,而不是一个列表。您必须在查询结果上调用 ToList 才能转换为列表,这会造成相当大的性能损失。
  • 其他方式的伙伴,更改为 IEnumerable 意味着您可以执行 UpdateTermInfo(某些 LINQ 查询),或任何其他返回 IEnumerable 的操作。
  • @MarcGravell 和 David - 不错 :)
【解决方案3】:

List 实现了IEnumerable,使用它会使事情变得更加灵活。如果一个实例出现在您不想使用 List 并想使用不同的集合对象的地方,它会轻松地从 IEnumerable 转换。

例如IEnumerable 允许您使用Arrays 和许多其他方式,而不是始终使用List

Inumerable 只是一个项目集合,与 List 不同,您可以在其中添加、删除、排序、使用 For Each、Count 等。

【讨论】:

    【解决方案4】:

    重构背后的主要思想是使方法更通用。你没有说你想要什么数据结构,只说你需要什么:你可以迭代它的元素。

    所以以后,当您认为 O(n) 搜索对您来说不够好时,您只需更改一行并继续前进。

    【讨论】:

      【解决方案5】:

      如果您使用 List,那么您将自己限制为仅使用 List 的具体实现,而与 IEnumerable 一样,您可以传入数组、列表、集合,因为它们都实现了该接口。

      【讨论】:

        猜你喜欢
        • 2023-02-12
        • 2012-02-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多