在 API 中返回的最佳集合类型是什么

发布于 2024-09-07 14:47:21 字数 262 浏览 3 评论 0原文

我一直认为,当拥有公共 API 时,返回数组比列表更好,但现在看来列表上的所有这些函数都可以通过 LINQ 等使用。

这里返回基元或对象集合的最佳实践是否已更改?

例如:

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

i have always thought that returning Arrays were better than lists when having a public API but it seems now there are all these functions on lists that are available through LINQ, etc.

Has the best practice changed here for returning collections of primitives or objects?

for example:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

墨落成白 2024-09-14 14:47:21

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

不要忘记 ReadOnlyCollection 它返回一个仍可以通过索引访问的不可变集合。

如果您使用 IEnumerable 并将您的类型释放到无法控制的荒野中,请注意这一点:

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,因为这样某些操作的执行速度会更快(获取计数、按索引访问项目、复制到另一个集合)。

就我个人而言,我希望看到框架包含并使用这样的接口:

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 之上的扩展方法来获取所有这些函数,但它们的性能不高。

As I generally only return immutable (unmodifiable) objects from properties/methods, this answer assumes you want to do the same.

Don't forget about ReadOnlyCollection<T> which returns an immutable collection that can still be accessed by index.

If you're using IEnumerable<T> and releasing your type into the uncontrollable wilderness, be wary of this:

class MyClass {
    private List<int> _list;
    public IEnumerable<int> Numbers {
        get { return _list; }
    }
}

As a user could do this and mess up the internal state of your class:

var list = (List<int>)myClass.Numbers;
list.Add(123);

This would violate the read-only intention for the property. In such cases, your getter should look like this:

    public IEnumerable<int> Numbers {
        get { return new ReadOnlyCollection<int>(_list); }
    }

Alternatively you could call _list.ToReadOnly(). I wrote it out in full to show the type.

That will stop anyone modifying your state (unless they use reflection, but that's really hard to stop unless you build immutable collections like those use in many functional programming languages, and that's a whole other story).

If you're returning read only collections, you're better off declaring the member as ReadOnlyCollection<T> as then certain actions perform faster (getting count, accessing items by index, copying to another collection).

Personally I'd like to see the framework include and use an interface like this:

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);
}

You can get all these functions using extension methods on top of IEnumerable<T> but they're not as performant.

终止放荡 2024-09-14 14:47:21

您希望集合不可变吗? IEnumerable
可变的? IList

您需要索引吗? IList

对于列表或数组,API 使用者具有添加、删除、删除、清除等的完整功能。

对于 IEnumerable,API消费者获得一个“包”的项目,没有特定的顺序,没有索引,也没有修改集合的方法。

在某些有限的情况下,您可能希望返回 IQueryable,但它们通常特定于零散地构建查询。

一般来说,我默认使用 IEnumerable。例如,我可能会使用 List 作为支持字段,但只想允许用户 Add(),而不是删除、清除或任何其他东西,所以我声明一个 public void Add(T item) ,它只是将项目添加到支持字段列表中。

Do you want the collection to be immutable? IEnumerable<T>
Mutable? IList<T>

Do you need indexes? IList<T>

With a list or array, the API consumer has full capability to add, remove, delete, clear, etc.

With an IEnumerable<T>, the API consumer gets a "bag" of items, with no particular order, no index, and no methods to modify the collection.

There are some limited circumstances in which you might want to return an IQueryable<T>, but they are often specific to building queries piecemeal.

In general, I'd default to IEnumerable<T>. I might use a List<T> as a backing field, but only want to allow the user to Add(), for example -- not to remove, clear, or anything else, so I declare a public void Add<T>(T item) that just adds the item to the backing field list.

错々过的事 2024-09-14 14:47:21

我认为最常用的类型是 IEnumerable

  • 通过 IEnumerable 返回类型,您可以使用 yield 关键字,这使得延迟枚举和执行您的方法。 (例如,一个常见的抱怨是 System.IO.Path.GetFiles() 不返回 IEnumerable 而是返回一个数组,这意味着当您调用该方法时,所有项目都需要枚举,无论您是否需要它们 - List 也有同样的缺点)
  • 大多数 LINQ 扩展方法都在 IEnumerable 上工作
  • 。 IEnumerable返回类型不假设有关调用者的任何特定信息。如果调用者需要一个列表或数组,他们总是可以创建一个。
  • IEnumerableListArray 实现,因此很容易更改方法的实现,并且仍然支持先前的返回类型。

I think the most commonly used type is IEnumerable<T>

  • With a IEnumerable<T> return type you can use the yield keyword and this enables delayed enumeration and execution of your method. (A common complaint for example is that the System.IO.Path.GetFiles() does NOT return a IEnumerable<T> but returns an Array which means that when you call the method all items need to be enumerated regardless if you need them or not. - You have the same disadvantage with List<T>)
  • Most LINQ extension methods work on an IEnumerable<T>
  • The IEnumerable<T> return type doesn't assume anything specific about the caller. If the caller needs a list or array they can always create one.
  • IEnumerable<T> is implemented by List<T> and Array and it is therefore easy to change the implementation of your method and still support the previous return type.
爱你是孤单的心事 2024-09-14 14:47:21

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

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

In addition to what the others have said I want to add that you should never return IQueryable unless you're retrieving the objects from some remote datasource. IQueryable is a query object that will fetch the results on behalf of the caller. When using LINQ, an IQueryable will usually take an expression tree that will be translated for use by some other system (e.g. SQL Server).

See http://weblogs.asp.net/fredriknormen/archive/2008/12/01/returning-iqueryable-lt-t-gt.aspx for more details.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文