是否存在IEnumerable<;T>;在C#中

本文关键字:gt 存在 lt 是否 IEnumerable | 更新日期: 2023-09-27 18:19:35

或者,如果T的枚举器只是列出所有元素,那么使用vector是否安全?

是否存在IEnumerable<;T>;在C#中

C++中不需要它,原因如下:

C#只支持动态多态性。因此,要创建一个可重用的算法,您需要一个所有迭代器都将实现的接口。这就是IEnumerator<T>,而IEnumerable<T>是用于返回迭代器的工厂。

另一方面,C++模板支持duck类型。这意味着您不需要通过接口约束泛型类型参数来访问成员——编译器将根据模板的每个实例化的名称查找成员。

C++容器和迭代器具有隐式接口,这些接口等效于.NET IEnumerable<T>IEnumerator<T>ICollection<T>IList<T>,即:

对于集装箱:

  • CCD_ 7和CCD_
  • begin()成员函数——满足对IEnumerable<T>::GetEnumerator()的需求
  • end()成员函数--而不是IEnumerator<T>::MoveNext()返回值

对于前向迭代器:

  • value_type typedef
  • operator++——而不是IEnumerator<T>::MoveNext()
  • operator*operator->——而不是IEnumerator<T>::Current
  • 来自operator*的引用返回类型--而不是IList<T>索引器setter
  • operator==operator!=——在.NET中没有真正的等价物,但容器的end()IEnumerator<T>::MoveNext()的返回值匹配

对于随机访问迭代器:

  • operator+operator-operator[]——代替IList<T>

如果您定义了这些,那么标准算法将适用于您的容器和迭代器。不需要接口,也不需要虚拟功能。不使用虚拟函数会使C++泛型代码比等效的.NET代码更快,有时甚至更快。


注意:在编写泛型算法时,最好使用std::begin(container)std::end(container),而不是容器成员函数。这允许您的算法除了用于STL容器之外,还用于原始数组(没有成员函数)。原始数组和原始指针满足容器和迭代器的所有其他要求,只有一个例外。

据我所知,如果我们严格地坚持这个问题,答案是否定的。人们一直在回复C++中可用的替代品是什么,这可能是很好的信息,但不是答案,OP很可能已经知道了。

我完全不同意"不需要它"的说法,只是C++和.NET标准库的设计不同。IEnumerable<>的主要功能它是多态的,因此它使调用方能够使用他想要的任何类(数组、列表、集合等),同时仍然提供编译时强类型,即使在库API中也是故障安全的。

C++中唯一的替代方案是模板。但C++模板并不是安全类型的运行时泛型,它们基本上是一种宏。因此,首先使用C++中的模板,您必须向任何需要使用模板的人提供整个模板源代码。此外,如果您使库API模板化,您将失去保证对它的调用将编译的能力,并且代码不会自动进行自文档编制。

我完全同情其他同时使用C#和C++的程序员,并对这一点感到沮丧。

然而,C++2X计划添加包括范围在内的功能(可能满足OP?);以及概念(解决了模板的弱/坏类型检查问题——Bjarne Stroustrup自己承认的缺陷)和模块(可能有助于也可能没有助于减少纯头模板的痛苦)。

标准的C++方法是传递两个迭代器:

template<typename ForwardIterator>
void some_function(ForwardIterator begin, ForwardIterator end)
{
    for (; begin != end; ++begin)
    {
        do_something_with(*begin);
    }
}

示例客户端代码:

std::vector<int> vec = {2, 3, 5, 7, 11, 13, 17, 19};
some_function(vec.begin(), vec.end());
std::list<int> lst = {2, 3, 5, 7, 11, 13, 17, 19};
some_function(lst.begin(), lst.end());
int arr[] = {2, 3, 5, 7, 11, 13, 17, 19};
some_function(arr + 0, arr + 8);

Yay通用编程!

IEnumerable<T>在概念上与vector非常不同。

IEnumerable提供对对象序列的仅向前只读访问,而不管哪个容器(如果有的话)容纳对象。vector实际上是一个容器本身。

在C++中,如果您希望在不提供容器详细信息的情况下提供对容器的访问,则约定是传入两个迭代器,表示容器的开始和结束。

一个很好的例子是累积的C++STL定义,它可以与IEnumerable<T>。骨料

在C++中

   int GetProduct(const vector<int>& v)
   {
         // We don't provide the container, but two iterators
         return std::accumulate(v.begin(), v.end(), 1, multiplies<int>());
   }

在C#中

  int GetProduct(IEnumerable<int> v)
  {
        v.Aggregate(1, (l, r) => l*r);
  }