C#迭代器设计的基本原理(与C+;+;)相比)
我发现了类似的话题:C#迭代器设计的基本原理(与C+;+;)相比),c#,iterator,C#,Iterator,我发现了类似的话题: 这基本上解决了Java迭代器(类似于C#)无法向后运行的问题 所以我想集中在极限——在C++迭代器中不知道它的极限,你自己把给定迭代器与极限进行比较。在C#中,迭代器知道的更多——您可以不与任何外部引用进行比较就知道迭代器是否有效 我更喜欢C++方式,因为一旦有迭代器,就可以设置任何迭代器作为限制。换句话说,如果您希望只获取少数元素而不是整个集合,则无需更改迭代器(在C++中)。对我来说,它更“纯净”(清晰) 当然,在设计C++时,MS当然知道这一点。那么C#way的优势
这基本上解决了Java迭代器(类似于C#)无法向后运行的问题
所以我想集中在极限——在C++迭代器中不知道它的极限,你自己把给定迭代器与极限进行比较。在C#中,迭代器知道的更多——您可以不与任何外部引用进行比较就知道迭代器是否有效
我更喜欢C++方式,因为一旦有迭代器,就可以设置任何迭代器作为限制。换句话说,如果您希望只获取少数元素而不是整个集合,则无需更改迭代器(在C++中)。对我来说,它更“纯净”(清晰)
当然,在设计C++时,MS当然知道这一点。那么C#way的优势是什么?哪种方法更强大(这将导致基于迭代器的更优雅的函数)。我错过了什么如果你对C + v+C++迭代器的思想有强烈的理解,请设计< <强> >,而不是限制它们(边界),请回答。 注意:(以防万一)请严格保持讨论的技术性。没有C++/C#flamewar
编辑 正如Tzaman所说,“将限制单独表示没有任何好处,因为除了一次遍历一个元素之外,没有其他方法可以实现。”然而,构建一个一次执行多个步骤的C#迭代器并不是那么困难,因此问题是——使用显式限制迭代器(如在C++中)是否有好处?如果是——什么 @乔恩, Edit1:假设您有一个函数foo,它在迭代器上执行某些操作(这个示例非常幼稚!) 现在,您想调用除最后10个元素之外的所有元素的函数栏bar(iter_from,iter_end-10); // C++ style
在C#(如果我没有弄错的话)中,您必须为该迭代器提供额外的方法来更改其限制,如下所示:
bar(iter.ChangeTheLimit(-10));
编辑2:在重读了你的文章之后,我感觉到了关键的不同。在C++中,您对集合的迭代器进行工作,在C++中,您对集合进行工作(迭代器在内部使用)。如果是的话,我仍然对C感到有点不舒服——迭代集合,当您发现有趣的元素时,您希望将所有元素从“这里”传递到末尾。在C++中,它非常简单,没有开销。在C#中,可以传递迭代器或集合(如果后者需要额外计算)。我将等待您的评论:-)
@汉斯,
我不是在比较苹果和桔子。公司。理论是这里的共同点,因此您有排序算法、分区等。您有集合(或序列,如Jon所喜欢)的概念。现在,问题是如何设计元素的访问,以用C语言或C++语言(或任何其他语言)编写优雅的算法。我想理解“我们这样做是因为……”的理由
我知道.NET迭代器和集合是独立的类。我知道访问元素和访问整个集合之间的区别。然而,C++中最常用的方法是使用迭代器——这样,尽管集合完全不同,但您可以使用列表和向量。另一方面,在C#中,你更喜欢写作
sort(IEnumerable<T> coll)
排序(IEnumerable coll)
代替功能
sort(IEnumerator<T> iter)
排序(IEnumerator iter)
对吗?因此,在这个意义上,我猜你不能把C迭代器作为C++迭代器,因为C ^不以和C++相同的方式表达相同的算法。或者正如Jon所指出的——在C语言中,你宁愿转换集合(跳过,取)而不是更改迭代器。我觉得C语言的设计更像是一种封装:一个序列运行或执行,与其他任何事情无关。将一个限额与另一个限额进行比较有何意义
如果您只想获取几个元素,那么LINQ提供了许多从一个序列构建另一个序列的方法,例如
foo.Take(10)
foo.Skip(10)
foo.Where(x => x.StartsWith("y"))
等
我认为将一个序列转换成另一个序列比用限制来指定更清晰,也更可组合。如果要将迭代器传递给另一个函数,但要将其限制为前几个元素,为什么还要传递限制?为什么不通过自我限制的转换序列呢
编辑:为了解决您的问题编辑:在C#(至少使用LINQ)中,您不会修改现有集合。您将从旧序列创建一个新序列。这是懒惰的;它不会创建新副本或类似的内容。对于LINQ to对象,这是使用IEnumerable
上的扩展方法执行的,因此任何序列都可以获得相同的功能
请注意,这并不局限于传统的集合—它可以是从日志文件中读取的一系列行(同样是惰性的)。您不需要任何关于集合本身的知识,只需要它是一个可以从中绘制项目的序列。IEnumerable
和IEnumerator
之间也有区别,前者表示序列,后者表示序列上的迭代器IEnumerator
很少在C#中显式使用,也很少被传递
现在,您的“除最后10个元素外的所有元素”的示例是一个棘手的示例,因为对于一般序列,您无法判断从结尾到到达结尾的10个元素。LINQto对象中没有显式地执行此操作。对于实现ICollection
或ICollection
的任何内容,您可以使用
Bar(list.Take(list.Count - 10))
但这不是很普遍。一个更通用的解决方案需要保持10个元素的循环缓冲区,有效地提前读取10个元素。老实说,我很少发现这是一项要求
那么C#way的优势是什么
封装一个。如果您不手动设置迭代序列,则更难搞乱迭代限制
C++示例:
std::vector<int> a;
std::vector<int> b;
std::vector<int>::iterator ba = a.begin();
std::vector<int>::iterator ea = a.end();
std::vector<int>::iterator bb = b.begin();
std::vector<int>::iterator eb = b.end();
// lots of code here
for(auto itr = ba; itr != eb; itr++) // iterator tries to "cross" vectors
// you get undefined behavior, depending
// on what you do with itr
std::向量a;
std::载体b;
std::vector::迭代器ba=a.begin();
std::vector::迭代器ea=a.end();
标准:v
std::vector<int> a;
std::vector<int> b;
std::vector<int>::iterator ba = a.begin();
std::vector<int>::iterator ea = a.end();
std::vector<int>::iterator bb = b.begin();
std::vector<int>::iterator eb = b.end();
// lots of code here
for(auto itr = ba; itr != eb; itr++) // iterator tries to "cross" vectors
// you get undefined behavior, depending
// on what you do with itr
for(int i = 0; i< 1000; ++i)
{
... // do something
if (i == 100)
i = 200; // skip from 100 to 200
}