2010-06-28 68 views
9

我一直认为返回数组比使用公共API时的列表要好,但现在似乎在列表中可以通过LINQ等获得所有这些函数。什么是在API中返回的最佳集合类型

为了返回原始对象或对象的集合,这里改变了最佳实践吗?

例如:

Order[] GetOrders(); 
List<Order> GetOrders(); 
IEnumerable<Order> GetOrders(); 
IQueryable<Order> Get Orders(); 
+0

请注意,以上所有类型都支持不同程度的Linq,可以通过'IEnumerable '或'IQueryable '。 – 2010-06-28 03:49:41

回答

5

我觉得最常用的类型是IEnumerable<T>

  • 有了可以使用yield关键字IEnumerable<T>返回类型,这使得你的方法延迟枚举和执行。 (例如,常见的投诉是System.IO.Path.GetFiles()不返回IEnumerable<T>,但返回一个Array,这意味着当您调用该方法时,无论您是否需要,都需要枚举所有项目。您有List<T>相同的缺点)
  • 大多数LINQ扩展方法上的IEnumerable<T>
  • IEnumerable<T>返回类型工作,不承担具体的有关呼叫者的东西。如果调用者需要一个列表或数组,他们总是可以创建一个。
  • IEnumerable<T>List<T>Array执行,因此很容易改变您的方法的实现,并仍然支持以前的返回类型。
+0

只要确保你不允许某人将你的'IEnumerable ''投射到例如'List '并且改变它,如果这会破坏类的不变量。查看我的答案了解更多详情。 – 2010-06-28 13:16:35

5

你想要集合是不可改变的吗? IEnumerable<T> 可变吗? IList<T>

你需要索引吗? IList<T>

与列表或阵列,该API消费者有充分的能力来添加,删除,删除,清除等

随着IEnumerable<T>,该API消费者获得一个项目的“包”,没有特别顺序,没有索引,也没有方法修改集合。

在一些有限的情况下,您可能想要返回IQueryable<T>,但它们通常专用于逐个构建查询。

一般而言,我会默认为IEnumerable<T>。我可能会使用List<T>作为后台字段,但只希望允许用户以Add()为例 - 不要删除,清除或其他任何内容,因此我声明public void Add<T>(T item)只是将该项添加到后台字段列表中。

+0

如果您不需要索引,请不要忘记ICollection 。 IList 实现ICollection ,并且只是添加索引器,IndexOf(T item),Insert(int index,T item)和RemoveAt(int index)。 – 2010-06-28 20:00:21

1

除了其他人所说的内容之外,我想补充说,除非您从某个远程数据源检索对象,否则不应该返回IQueryable。 IQueryable是一个查询对象,它将代表调用者获取结果。当使用LINQ时,IQuearyable通常会使用表达式树来转换以供其他系统(例如Sql Server)使用。

请参阅http://weblogs.asp.net/fredriknormen/archive/2008/12/01/returning-iqueryable-lt-t-gt.aspx了解更多详情。

5

正如我通常只从属性/方法返回不可变(不可修改)的对象,这个答案假设你想要做同样的事情。

不要忘了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); 

这会违反财产的只读意图。在这种情况下,您的吸气器应如下所示:

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>顶部扩展方法所有这些功能,但它们没有高性能的。

相关问题