必须IList的是有限的? [英] Must IList be finite?

查看:215
本文介绍了必须IList的是有限的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

必须.NET的的IList 是有限的?假设我写一个类FibonacciList实施的IList< BigInteger的>

Must .NET's IList be finite? Suppose I write a class FibonacciList implementing IList<BigInteger>

  • 的属性Item [N]返回第n个Fibonacci数。
  • 的IsReadOnly返回true。
  • 属性
  • 在该方法的IndexOf和包含我们就可以实现轻松不够,因为Fibonacci序列增加 - 测试是否数m是斐波那契数,我们只需要计算的有限的最多的m序列Fibonacci数
  • 在该方法GetEnumerator()做正确的事
  • The property Item[n] returns the nth Fibonacci number.
  • The property IsReadOnly returns true.
  • The methods IndexOf and Contains we can implement easily enough because the Fibonacci sequence is increasing - to test if the number m is Fibonacci, we need only to compute the finite sequence of Fibonacci numbers up to m.
  • The method GetEnumerator() doing the right thing

我们现在已经实现了所有预期的只读ILists除了计数方法()。

We've now implemented all the methods expected of read-only ILists except Count().

这是很酷的,或IList中的滥用?

Is this cool, or an abuse of IList?

Fibonacci数得到不切实际的大快(因此的IList&LT; BigInteger的&GT; 以上)。有界无限序列可能是更明智的,它可以实现的IList&LT;长&GT; 的IList&LT;双&GT;

Fibonacci numbers get impractically big quickly (hence IList<BigInteger> above) . A bounded infinite sequence might be more sensible, it could implement IList<long> or IList<double>.

附录二:斐波那契序列可能是一个坏榜样,因为计算遥远的价值是昂贵的 - 找n个值一个人来计算所有以前的值。因此,随着Mošmondor说,人们还不如让一个IEnumerable,并使用 .ElementAt 。然而有没有快速计算以前的值存在其它序列,其中一个可以计算远处值。 (圆周率令人惊讶的是数字是这样的序列)。这些序列是更多的'listy,他们真正支持随机访问。

Addendum II: Fibonacci sequence may have been a bad example, because computing distant values is expensive - to find the nth value one has to compute all earlier values. Thus as Mošmondor said, one might as well make it an IEnumerable and use .ElementAt. However there exist other sequences where one can compute distant values quickly without computing earlier values. (Surprisingly the digits of pi are such a sequence). These sequences are more 'listy', they truly support random access.

编辑:没有人反驳了无限IEnumerables。他们如何处理计数()?

No-one argues against infinite IEnumerables. How do they handle Count()?

推荐答案

对于大多数开发人员来说,的IList 的ICollection 意味着你有一个pre-评估,在内存中收集的工作。随着的IList 明确,有固定时间的隐性契约添加 * 和索引操作。这就是为什么 的LinkedList&LT; T&GT; 不执行的IList&LT; T&GT; 。我会考虑FibonacciList是违反这一默示合同。

To most developers, IList and ICollection imply that you have a pre-evaluated, in-memory collection to work with. With IList specifically, there is an implicit contract of constant-time Add* and indexing operations. This is why LinkedList<T> does not implement IList<T>. I would consider a FibonacciList to be a violation of this implied contract.

请注意从最近的MSDN杂志文章讨论的原因,将读只有集合接口到.NET 4.5:

Note the following paragraph from a recent MSDN Magazine article discussing the reasons for adding read-only collection interfaces to .NET 4.5:

的IEnumerable&LT; T&GT; 足以满足大多数情况下的应对类型的集合,但有时你需要更多的权力比它规定:

IEnumerable<T> is sufficient for most scenarios that deal with collections of types, but sometimes you need more power than it provides:

      
  • 物化:的IEnumerable&LT; T&GT; 不允许你前preSS集合是否已经可用(物化),还是它的计算每次迭代它(例如,如果它再presents LINQ查询)。当一个算法需要多次迭代过的收集,这可能会导致性能下降,如果计算所述序列是昂贵;它也可能导致因身份不匹配的微妙的错误时,被再次在随后的通过生成的对象。
  •   
  • Materialization: IEnumerable<T> does not allow you to express whether the collection is already available ("materialized") or whether it’s computed every time you iterate over it (for example, if it represents a LINQ query). When an algorithm requires multiple iterations over the collection, this can result in performance degradation if computing the sequence is expensive; it can also cause subtle bugs because of identity mismatches when objects are being generated again on subsequent passes.

正如其他人所指出的,还有,你会回到什么 .Count之间的问题。

As others have pointed out, there is also the question of what you would return for .Count.

这是完全正常使用中的数据,例如收集的IEnumerable 的IQueryable ,因为有一个期望,这些类型可以被懒惰地评估。

It's perfectly fine to use IEnumerable or IQueryable in for such collections of data, because there is an expectation that these types can be lazily evaluated.

关于编辑1: .Count之间()不受的IEnumerable&LT实施; T&GT; 接口:是一个扩展方法。这样,开发者需要期望它可以采取任何的时间,并且他们需要避免调用它的情况下它们实际上并不需要知道的项目数。例如,如果你只是想知道是否一个的IEnumerable&LT; T&GT; 拥有的任意的项目,最好使用。任何()。如果你知道,有要处理的项目的最大数量,您可以使用。取()。如果收藏有超过 int.MaxValue 在它的项目, .Count之间()会遇到一个操作溢出。因此,有一些解决方法,可以帮助减少与无穷序列​​相关的危险。显然,如果程序员没有考虑这些可能性考虑在内,但仍可能会造成问题,但。

Regarding Edit 1: .Count() is not implemented by the IEnumerable<T> interface: it is an extension method. As such, developers need to expect that it can take any amount of time, and they need to avoid calling it in cases where they don't actually need to know the number of items. For example, if you just want to know whether an IEnumerable<T> has any items, it's better to use .Any(). If you know that there's a maximum number of items you want to deal with, you can use .Take(). If a collection has more than int.MaxValue items in it, .Count() will encounter an operation overflow. So there are some workarounds that can help to reduce the danger associated with infinite sequences. Obviously if programmers haven't taken these possibilities into account, it can still cause problems, though.

关于编辑2:如果你计划实现你的序列的方式,分度是恒定的时间,即方便地解决了我的主要点pretty的。 Sixlettervariables的回答仍然是成立的,但。

Regarding Edit 2: If you're planning to implement your sequence in a way that indexing is constant-time, that addresses my main point pretty handily. Sixlettervariables's answer still holds true, though.

*显然有更多的这样:添加预计只会工作,如果 IList.IsFixedSize 返回。修改只有当的IsReadOnly 返回false等的IList 是摆在首位不善深思熟虑的接口:这可能最终通过引入只读集合接口在.NET 4.5

*Obviously there's more to this: Add is only expected to work if IList.IsFixedSize returns false. Modification is only possible if IsReadOnly returns false, etc. IList was a poorly-thought-out interface in the first place: a fact which may finally be remedied by the introduction of read-only collection interfaces in .NET 4.5.

在给予这方面的一些额外的想法,我已经来到了个人的看法是的IEnumerable&LT;&GT; ,不应为无穷大任。除了物化的方法,如 .ToList(),LINQ有几个非流如 .OrderBy操作()这必须消耗整个的IEnumerable&LT;&GT; 之前的第一个结果可以退换。既然有这么多方法假定的IEnumerable&LT;&GT; 是安全的全部遍历,这将是一个违反了里氏替换原则,以产生一个 IEnumerable的&LT;&GT; 这是固有的不安全穿越无限

Having given this some additional thought, I've come to the personal opinion that IEnumerable<>s should not be infinite either. In addition to materializing methods like .ToList(), LINQ has several non-streaming operations like .OrderBy() which must consume the entire IEnumerable<> before the first result can be returned. Since so many methods assume IEnumerable<>s are safe to traverse in their entirety, it would be a violation of the Liskov Substitution Principle to produce an IEnumerable<> that is inherently unsafe to traverse indefinitely.

如果你发现你的应用程序往往需要斐波那契序列IEnumerables的部分,我建议建立类似于 Enumerable.Range(INT,INT),系统允许用户定义一个起始和结束索引

If you find that your application often requires segments of the Fibonacci sequence as IEnumerables, I'd suggest creating a method with a signature similar to Enumerable.Range(int, int), which allows the user to define a starting and ending index.

如果你想踏上哎呀,飕飕的项目,你可以想见,开发一个斐波那契型的IQueryable&LT;&GT; 提供商,用户可以使用有限的的LINQ查询语法子集,像这样:

If you'd like to embark on a Gee-Whiz project, you could conceivably develop a Fibonacci-based IQueryable<> provider, where users could use a limited subset of LINQ query syntax, like so:

// LINQ to Fibonacci!
var fibQuery = from n in Fibonacci.Numbers // (returns an IQueryable<>)
               where n.Index > 5 && n.Value < 20000
               select n.Value;
var fibCount = fibQuery.Count();
var fibList = fibQuery.ToList();

由于您的查询,提供者将必须评估的动力其中,条款为lambda EX pressions,你可以有足够的控制来实现计数的方法和 .GetEnumerator()的方式,以确保查询足以限制产生一个真正的答案,或者抛出一个异常,如一旦调用该方法

Since your query provider would have the power to evaluate the where clauses as lambda expressions, you could have enough control to implement Count methods and .GetEnumerator() in a way as to ensure that the query is restrictive enough to produce a real answer, or throw an exception as soon as the method is called.

但这种恶臭的是聪明,而且很可能是任何现实生活中的软件一个非常糟糕的主意。

But this reeks of being clever, and would probably be a really bad idea for any real-life software.

这篇关于必须IList的是有限的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆