我应该喜欢IEnumerable 还是Arrays?

在我工作的许多项目中,每当我必须返回一个只读集合时,我使用IEnumerable接口并使其类型特定如下:

 Public ReadOnly Property GetValues() As IEnumerable(Of Integer) Get 'code to return the values' End Get End Property 

大多数时候,我返回一个List,但是在一些函数和只读属性中,我返回一个数组,这个目的也可以通过扩展方法的礼貌来实现。

我的问题是我是否通过返回IEnumerable而不是特定类型(例如: ListHashSetStackArray s)来违反任何设计原则

我通常也喜欢IEnumerable 。 主要的是问自己从方法返回的实际(甚至是最小)function(或者在方法参数的情况下传递给它)。

如果你需要做的就是对结果集进行枚举,那么IEnumerable就是这样做的。 不多也不少。 这使您可以灵活地在某些情况下返回更多特定类型,如果需要,而不会破坏方法的足迹。

大卫的回答几乎涵盖了它; IEnumerable是一般的最佳实践。 您可以通过查看大多数较新的框架方法来看到这一点。

我只是想补充一点,因为你在原始问题中指定了只读集合,你可以通过在返回IEnumerable实例之前调用.ToList().AsReadOnly()来强制执行此操作。 这将创建一个ReadOnlyCollection的具体实例供您返回。 你的返回类型应该仍然是IEnumerable ,因为调用者不需要知道你是专门返回一个ReadOnlyCollection ,但这样你就可以防止调用者在脚中射击自己。

(如果没有这一步,调用者可以尝试将IEnumerable从你的方法转换为List 。如果转换成功,那么如果这是你最初使用的那个,那么调用者就可以修改您在方法内操作的相同列表,可能会产生意外后果。)

我个人认为从API返回IEnumerable强烈暗示实现可能使用延迟评估。

知道可以使用延迟评估对于调用者来说可能很重要,因为它意味着:

  • 多次迭代结果(例如,获得计数然后访问数据)将导致评估不止一次。

  • 迭代结果时,可以从API抛出exception:

例如

 IEnumerable LazyEvaluatedApi() { } ... IEnumerable result = LazyEvaluatedApi(); ... foreach(MyObject item in result) // Exception from LazyEvaluatedApi may be thrown here. { } 

如果您认为任何实现都不需要使用延迟评估(例如数据访问层API),我宁愿返回ICollectionIList 。 除了让调用者访问Count属性( ICollectionIList )和索引器(仅IList )之外,您还清楚地表明不会进行延迟评估。

返回ICollectionIList ,具体实现通常可能会返回List 。 如果列表是只读的很重要,那么返回List.AsReadOnly()

这取决于你想做什么以及你打算“违反”。 这取决于:

  1. 如果您希望对象返回的集合可以被外部代码更改,则必须返回可修改的类型,即List <>,HashSet <> Stack <>或任何其他允许修改的类型
  2. 如果您希望“收集用户”只是迭代收集项而不修改收集本身,这是正确的选择

请记住,许多优秀的设计大师和原则更喜欢返回IEnumerable <> over modifiable-collection-ready

返回IEnumerable很好。 虽然注意如果T是引用类型,则调用者可以修改对象。

您应该返回提供所需最低级别function的最常规类型。 在这种情况下,如果调用者只需要对数据进行交互,那么IEnumerable比ListHashSet或任何其他集合类型更合适。 这样,您的调用者仍然可以与方法的实现分离,并且您可以在将来更改方法实现,而不会中断调用者。

如果你不需要ListHashSet等提供的任何额外function,那么返回IEnumerable就可以了,imo。

返回您认为最合适的任何类型; 如果你只需要遍历集合或者用它们做LINQ-y的东西,那么IEnumerable在大多数情况下都是好的。

当您确实需要返回“更丰富”的类型时,请考虑返回一个接口而不是具体类型 – IList而不是ListISet而不是HashSet等 – 以便您的实现如有必要,可以在不破坏任何调用代码的情况下进行更改。

这取决于。 如果您打算使用您的方法仅仅是枚举,那么IEnumerable是正确的选择。

如果索引查找等特定function很重要,那么您可能会更具体。

也就是说,您始终可以将IEnumerable包装在LINQ表达式中并将其用作任何内容。 如果返回的类型已经支持LINQ表达式中使用的function,那么聪明的编译器可以优化该表达式。

IEnumerable查询速度更快,因为它可以组合查询逻辑。 我通常使用数组来删除或更改值,因为我不想在我影响它时更改我的集合