在我工作的许多项目中,每当我必须返回一个只读集合时,我使用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)
答案 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)
这取决于你想做什么以及你打算“违反”。 这取决于:
请记住,许多优秀的设计专家和原则更喜欢返回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查询速度更快,因为它可以组合查询逻辑。我通常使用数组来删除或更改值,因为我不想在我影响它时更改我的集合