C# Visual Studio代码分析规则-“;“不要公开通用列表”;

C# Visual Studio代码分析规则-“;“不要公开通用列表”;,c#,linq,extension-methods,code-analysis,fxcop,C#,Linq,Extension Methods,Code Analysis,Fxcop,如果我的所有方法都需要公开一个集合,那么我需要使用Linq扩展名.ToList(),几乎在我所有代码中需要使用列表或用户集合的任何地方 如果是这样,.ToList()会忽略规则,对吗?或者有没有一种技术,比如复制某个列表来修复冲突并仍然返回一个列表?我禁用了该规则,因为我觉得它不是一个有效的规则。如果要返回包含O(1)计数且不是对内部字段的直接引用的集合,List是最佳选择 我不太理解您的情况,但听起来您有一个方法可以返回对一些内部数据的LINQ查询。如果是这种情况,那么对数据使用.ToList

如果我的所有方法都需要公开一个集合,那么我需要使用Linq扩展名.ToList(),几乎在我所有代码中需要使用列表或用户集合的任何地方


如果是这样,.ToList()会忽略规则,对吗?或者有没有一种技术,比如复制某个列表来修复冲突并仍然返回一个列表?

我禁用了该规则,因为我觉得它不是一个有效的规则。如果要返回包含
O(1)
计数且不是对内部字段的直接引用的集合,
List
是最佳选择


我不太理解您的情况,但听起来您有一个方法可以返回对一些内部数据的LINQ查询。如果是这种情况,那么对数据使用
.ToList()
是合适的,因为您可能不希望将来对内部字段的修改影响方法的返回值。在这种情况下,没有理由不将其作为
列表公开

记住,所有这些规则都是为框架开发人员编写的。除非您也在编写框架,否则它们中的许多可能都不合适


你必须对每一条规则做出判断,看看它是否适合你的情况。我喜欢使用分析,因为它有时确实会发现一些错误,但我总是会禁用某些规则(例如,我经常会有一个
捕获异常作为最终捕获,因为我需要记录所有类型的错误,即使它们无法处理)。

这条规则确实很嘈杂,但是有一些非常合理的理由可以避免在库代码中列出
List
。这完全取决于上下文。以下是在禁用规则或抑制给定的事件之前要考虑的一些事情:

  • List
    对于输入参数来说通常是一个糟糕的选择,因为它迫使调用方不必要地复制数据。我见过很多代码,它们将参数声明为
    List
    T[]
    ,而
    IEnumerable
    就足够了

  • List
    对于属性来说也是一个糟糕的选择。考虑下面的备选方案:

    public class Course {
        public List<Course> Prerequisites { get; }
    }
    public class Course {
        public Collection<Course> Prerequisites { get; }
    }
    
    公共课{
    公共列表先决条件{get;}
    }
    公共课{
    公共集合先决条件{get;}
    }
    
    其目的是调用方可以通过修改集合来更改课程的先决条件。在这种情况下,如果我们使用
    列表
    ,那么当先决条件发生变化时,
    课程
    类无法得到通知,因为
    列表
    不提供任何修改回调。因此,在此上下文中使用
    List
    就像拥有任意多个公共字段一样。另一方面,我们可以将
    Collection
    子类化,并覆盖它的虚拟对象以获得更改通知

List
将集合的全部所有权转移给调用者时,作为返回值最有效。这就是为什么
Enumerable.ToList()
实际上是完全合理的,并且它没有违反规则的精神


现在我考虑一下,允许
List
作为方法的返回值,但继续标记
List
属性和参数可能会大大提高规则的信噪比…

@Fraga,不,这不是作弊,而且我经常出于各种原因禁用某些规则。它们不是普遍的真理,通常会妨碍设计高质量的库。它们更像是“指南”。如果您希望返回列表,则最好使用IList作为返回类型。我通常仍然使用
IEnumerable
作为返回类型(即使我调用
.ToList()
.ToArray()
),因为这给了实现方法更大的灵活性。当底层对象是
IList
时,大多数LINQ函数都足够智能,可以优化访问。特别是,
.Count()
.ElementAt()
仍然是O(1)操作,因此返回
IEnumerable
@R不会对性能造成重大影响。我认为,问题在于,如果返回
列表
,则会暴露实现细节。如果您的函数以后使用了一些不同的数据结构,那么更改返回类型将是一个破坏性的更改,因此您可能最终创建一个副本或包装器来维护公共接口。您必须决定希望在公共合同中保证多少信息,而且越少越好。@Fraga,Microsoft自己的程序集不遵守此规则(请参见System.Core),因此这绝对不是一个不变的事实。如果
课程
只想在其先决条件更改时得到通知,那么,
BindingList
将是一个不错的选择。它有您可以订阅的事件,而不必像
Collection
@benvoigt那样派生新类。还有
可观察收集
。我的观点不是说
Collection
一定是最好的选择,而是说
List
在这种情况下是一个糟糕的选择。