我应该喜欢IEnumerable <t>还是Arrays?</t>

时间:2011-03-01 15:30:44

标签: c# .net vb.net design-principles

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

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

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

我的问题是我违反了任何设计原则,返回IEnumerable<T>而不是特定类型(例如:List<T>HashSet<T>Stack<T>或{{ 1}} S)

8 个答案:

答案 0 :(得分:33)

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

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

答案 1 :(得分:18)

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

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

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

答案 2 :(得分:13)

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

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

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

  • 在迭代结果时,可以从API抛出异常:

e.g。

IEnumerable<MyObject> LazyEvaluatedApi()
{
}

...

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

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

返回ICollection<T>IList<T>时,您的具体实施通常可能会返回List<T>。如果列表是只读的很重要,那么返回List<T>.AsReadOnly()

答案 3 :(得分:3)

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

  1. 如果您希望对象返回的集合可以被外部代码更改,则必须返回可修改的类型,即List&lt;&gt;,HashSet&lt;&gt;堆&LT;&GT;或任何其他允许修改的内容
  2. 如果您希望“收集用户”只是迭代收集项而不修改收藏本身,那么这是正确的选择
  3. 请记住,许多优秀的设计专家和原则更喜欢返回IEnumerable&lt;&gt; over modifiable-collection-ready

答案 4 :(得分:2)

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

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

答案 5 :(得分:0)

如果您不需要List<T>HashSet<T>等提供的任何额外功能,则返回IEnumerable<T>即可,imo。

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

当您确实需要返回“更丰富”的类型时,请考虑返回一个界面而不是具体类型 - IList<T>而不是List<T>ISet<T>而不是HashSet<T>等等 - 这样,如果有必要,您的实现将来可以更改,而不会破坏任何调用代码。

答案 6 :(得分:0)

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

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

也就是说,你总是可以将你的IEnumerable包装在一个LINQ表达式中并将其用作任何东西。如果返回的类型已经支持LINQ表达式中使用的功能,那么聪明的编译器可以优化该表达式。

答案 7 :(得分:0)

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