Is There a Standard C++ Equivalent of Ienumerable<T> in C#

Is there a standard C++ equivalent of IEnumerableT in C#?

It isn't needed in C++, and here's why:

C# only supports dynamic polymorphism. So to create a reusable algorithm, you need an interface which all iterators will implement. That's IEnumerator<T>, and IEnumerable<T> is a factory for returning an iterator.

C++ templates, on the other hand, support duck typing. That means you don't need to constrain a generic type parameter by an interface in order to access members -- the compiler will look up members by name for each individual instantiation of the template.

C++ containers and iterators have implicit interfaces which is equivalent to .NET IEnumerable<T>, IEnumerator<T>, ICollection<T>, IList<T>, namely:

For containers:

  • iterator and const_iterator typedefs
  • begin() member function -- fills the need for IEnumerable<T>::GetEnumerator()
  • end() member function -- instead of IEnumerator<T>::MoveNext() return value

For forward iterators:

  • value_type typedef
  • operator++ -- instead of IEnumerator<T>::MoveNext()
  • operator* and operator-> -- instead of IEnumerator<T>::Current
  • reference return type from operator* -- instead of IList<T> indexer setter
  • operator== and operator!= -- no true equivalent in .NET, but with container's end() matches IEnumerator<T>::MoveNext() return value

For random access iterators:

  • operator+, operator-, operator[] -- instead of IList<T>

If you define these, then standard algorithms will work with your container and iterator. No interface is needed, no virtual functions are needed. Not using virtual functions makes C++ generic code faster than equivalent .NET code, sometimes much faster.


Note: when writing generic algorithms, it's best to use std::begin(container) and std::end(container) instead of the container member functions. That allows your algorithm to be used with raw arrays (which don't have member functions) in addition to the STL containers. Raw arrays and raw pointers satisfy all other requirements of containers and iterators, with this single exception.

What is the simplest way to get generic IEnumerableT from System.Collections.IEnumerable?

Simplest and shortest is with LINQ. You can enumerate it without LINQ:

foreach (T item in IEnumerableCollection)

and this is pretty much what .Cast<T>() does:

static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source) {
foreach (object obj in source) yield return (TResult)obj;
}

IEnumerableT in C#

Well, the first compiler error I get is that it complains that:

Using the generic type 'System.Collections.Generic.IEnumerator' requires '1' type arguments

This is on line 16, this one:

IEnumerator IEnumerable.GetEnumerator()

Fixing that by adding a using directive for the System.Collections namespace (tip: place the cursor just after IEnumerator, on the r at the end of the word, and hit Ctrl+. (ctrl + the dot-key), it should suggest you add a "using System.Collections;" directive, do that).

Then it compiles, and runs. Does that match what you expect?

Also, note that you should always post the actual error messages you're getting, this way we're not barking up the wrong tree if there's something else wrong with your code that we're not seeing at first glance.

Additionally, you can simplify this very common implementation of IEnumerable<T> by calling one of the methods from the other, hence I would simplify the implementation of the second methods like this:

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator(); // this will return the one
// available through the object reference
// ie. "IEnumerator<int> GetEnumerator"
}

this way you only implement the actual enumerator code once.

And finally see Earwicker's answer as well, it shows a better (in my opinion at least) way to write this whole code.

Freely convert between ListT and IEnumerableT

List<string> myList = new List<string>();
IEnumerable<string> myEnumerable = myList;
List<string> listAgain = myEnumerable.ToList();

Why IEnumerableT is defined as IEnumerableout T, not IEnumerableT

More information can be found here.

The out makes the type parameter covariant. That is, you can use either the type or any derived types. Note that out only works this way with generics, it has a different meaning when used in method signatures (though you probably already knew that).

Here is the example taken from the referenced page:

// Covariant interface. 
interface ICovariant<out R> { }

// Extending covariant interface.
interface IExtCovariant<out R> : ICovariant<R> { }

// Implementing covariant interface.
class Sample<R> : ICovariant<R> { }

class Program
{
static void Test()
{
ICovariant<Object> iobj = new Sample<Object>();
ICovariant<String> istr = new Sample<String>();

// You can assign istr to iobj because
// the ICovariant interface is covariant.
iobj = istr;
}
}

As you can see, the out in the interface signature allows
you to assign an ICovariant<String> to an ICovariant<Object> variable, as String derives from Object. Without the out keyword, you would be unable to do this, as the types would be different.

You can read more about covariance (and the related contravariance) here.

As other answers have pointed out, IEnumerable was only made covariant in .NET 4. Trying to write code such as:

IEnumerable<Object> strings = new List<string>();

will compile in .NET 4 and later versions, but not in previous versions.

Existing methods to emulate C# concept of deferred IEnumerableT in C++?

I re-read your question and I actually think this can be servicable, but it's definitely not ideal without C++11.

You can consider boost::function<boost::optional<T>()> (yay Boost) as a range. The semantics of this range are super simple- you invoke it, and when it's finished, it gives back an empty optional instead of a value.

For output operations like push_back, you can consider a boost::function<void(T)> that will accept the value and then do whatever you need with it. However generally, these aren't that useful, as most functions can be written as returning a modified range, then the caller can simply use that range directly rather than requiring to take an output range.

Not having lambdas here is a total bitch, but you can look into e.g. Boost.Phoenix/Lambda to help.

Equivalence of Observable.Do for Enumerable

LINQ query operators are generally meant to be free from side-effects. You could just use a foreach loop to "do" your thing.

Or do it in a Select or Where method if you don't care about side effects:

enumerable.Select(x => { /*do something here */ return x; })

For a List<T>, there is a ForEach extension method that can be used to execute an Action<T> for each element.

Are IEnumerableT, TaskT and IDisposable hard coded in the C# compiler?

Sort-of.

The compiler has lists of "special" (used in the type-system / binder) and "well-known" (referenced by generated code) types and members, which are hard-coded by name in Roslyn source. However, all that it cares about are the names & methods / signatures of these types / members; you can still write your own mscorlib (and people have done this) as long as it has them.

See

  • http://sourceroslyn.io/#Microsoft.CodeAnalysis/SpecialType.cs
  • http://sourceroslyn.io/#Microsoft.CodeAnalysis/SpecialMember.cs
  • http://sourceroslyn.io/#Microsoft.CodeAnalysis/WellKnownTypes.cs
  • http://sourceroslyn.io/#Microsoft.CodeAnalysis/Symbols/WellKnownMemberNames.cs

LINQ equivalent of foreach for IEnumerableT

There is no ForEach extension for IEnumerable; only for List<T>. So you could do

items.ToList().ForEach(i => i.DoStuff());

Alternatively, write your own ForEach extension method:

public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
{
foreach(T item in enumeration)
{
action(item);
}
}


Related Topics



Leave a reply



Submit