我一直认为在使用公共API时,返回的数组比列表更好,但现在似乎所有这些函数都可以通过LINQ等获得。
此处是否更改了返回基元或对象集合的最佳实践?
例如:
Order[] GetOrders();
List<Order> GetOrders();
IEnumerable<Order> GetOrders();
IQueryable<Order> Get Orders();
答案 0 :(得分:6)
您希望集合是不可变的吗? IEnumerable<T>
可变的? IList<T>
你需要索引吗? IList<T>
使用列表或数组,API使用者具有添加,删除,删除,清除等功能。
使用IEnumerable<T>
,API使用者获得一个“包”项,没有特定的顺序,没有索引,也没有修改集合的方法。
在某些有限的情况下,您可能希望返回IQueryable<T>
,但它们通常专门用于逐步构建查询。
一般情况下,我默认为IEnumerable<T>
。我可能会使用List<T>
作为支持字段,但只希望允许用户Add()
,例如 - 不要删除,清除或其他任何内容,因此我声明{{1}只是将项添加到支持字段列表。
答案 1 :(得分:6)
由于我通常只从属性/方法返回不可变(不可修改)的对象,所以这个答案假定你想要做同样的事情。
不要忘记ReadOnlyCollection<T>
返回一个仍然可以通过索引访问的不可变集合。
如果你正在使用IEnumerable<T>
并将你的类型释放到无法控制的荒野中,请注意这一点:
class MyClass {
private List<int> _list;
public IEnumerable<int> Numbers {
get { return _list; }
}
}
用户可以这样做并弄乱你班级的内部状态:
var list = (List<int>)myClass.Numbers;
list.Add(123);
这违反了该物业的只读意图。在这种情况下,你的getter应该是这样的:
public IEnumerable<int> Numbers {
get { return new ReadOnlyCollection<int>(_list); }
}
或者您可以致电_list.ToReadOnly()
。我完整地写出来以显示类型。
这将阻止任何人修改你的状态(除非他们使用反射,但除非你构建像许多函数式编程语言中使用的那些不可变集合,否则这很难停止,而这是另一个故事)。
如果您要返回只读集合,最好将成员声明为ReadOnlyCollection<T>
,然后某些操作执行得更快(获取计数,按索引访问项目,复制到另一个集合)。
我个人希望看到框架包含并使用这样的界面:
public interface IReadOnlyCollection<T> : IEnumerable<T>
{
T this[int index] { get; }
int Count { get; }
bool Contains(T item);
void CopyTo(T[] array, int arrayIndex);
int IndexOf(T item);
}
您可以使用IEnumerable<T>
之上的扩展方法获取所有这些功能,但它们并不具备效果。
答案 2 :(得分:5)
我认为最常用的类型是IEnumerable<T>
IEnumerable<T>
返回类型,您可以使用yield
关键字,这可以启用延迟枚举和方法执行。 (例如,常见的抱怨是System.IO.Path.GetFiles()不返回IEnumerable<T>
但返回一个数组,这意味着当您调用该方法时,无论您是否需要它们,都需要枚举所有项目或不 - 。List<T>
)IEnumerable<T>
IEnumerable<T>
返回类型不会假设有关调用者的任何具体内容。如果调用者需要列表或数组,他们总是可以创建一个。IEnumerable<T>
由List<T>
和Array
实施,因此很容易更改方法的实现并仍然支持之前的返回类型。答案 3 :(得分:1)
除了其他人所说的内容之外,我想补充一点,除非您从某个远程数据源检索对象,否则不应该返回IQueryable
。 IQueryable
是一个查询对象,它将代表调用者获取结果。使用LINQ时,IQueryable
通常会使用一个表达式树,该表达式树将被翻译以供其他系统(例如SQL Server)使用。
有关详细信息,请参阅http://weblogs.asp.net/fredriknormen/archive/2008/12/01/returning-iqueryable-lt-t-gt.aspx。