I had started learning iterator methods and implementation of IEnumerators in c#. I got confused at a point regarding the yield return statement.
Suppose, I create an iterator method 'Iterator()' and I have a collection 'myCollection' containing items of type 'TCustom'. myCollection is a collection type that implements 'IEnumerable' but, type 'TCustom' does not implement it.
IEnumerable Iterator()
{
foreach(TCustom item in myCollection)
{
yield return item;
}
}
class RandomCollection : IEnumerable{....}
class TCustom {....}
RandomCollection myCollection = new RandomCollection();
so the yield statement is returning 'item' object of type 'TCustom' from 'myCollection'. If 'TCustom' is a custom type created from my source code, does it have to implement IEnumerable interface? And if type 'TCustom' does not implement 'IEnumerable' interface, can it be a return type of yield return statement?
(yield return item;)
IEnumerable is an interface that defines one method GetEnumerator which returns an IEnumerator interface, this in turn allows readonly access to a collection. A collection that implements IEnumerable can be used with a foreach statement.
Definition
IEnumerable
public IEnumerator GetEnumerator();
IEnumerator
public object Current;
public void Reset();
public bool MoveNext();
example code from codebetter.com
An IEnumerator is a thing that can enumerate: it has the Current property and the MoveNext and Reset methods (which in .NET code you probably won't call explicitly, though you could).
An IEnumerable is a thing that can be enumerated...which simply means that it has a GetEnumerator method that returns an IEnumerator.
Which do you use? The only reason to use IEnumerator is if you have something that has a nonstandard way of enumerating (that is, of returning its various elements one-by-one), and you need to define how that works. You'd create a new class implementing IEnumerator. But you'd still need to return that IEnumerator in an IEnumerable class.
For a look at what an enumerator (implementing IEnumerator<T>) looks like, see any Enumerator<T> class, such as the ones contained in List<T>, Queue<T>, or Stack<T>. For a look at a class implementing IEnumerable, see any standard collection class.
Related
I have a simple class, MyClass, which already has the Reset(), MoveNext(), and Current pieces. But it doesn't provide an iterator, it just exposes those components.
I started with this:
public IEnumerator<MyClass> GetEnumerator()
{
Reset();
while (MoveNext())
yield return Current;
}
Which triggers the following error:
CS1579 foreach statement cannot operate on variables of type 'IEnumerator' because 'IEnumerator' does not contain a public instance definition for 'GetEnumerator'
I tried a bunch of other approaches, but no joy.
Would someone point me in the right direction?
Thanks!
I'm guessing your code does something like
foreach(var variable in collection.GetEnumerator())
{
//do some stuff
}
You can leave out the GetEnumerator call. If you class implements IEnumerable it wil be called automatically.
So just:
foreach(var variable in collection)
{
//do some stuff
}
Key points:
You should call foreach on the collection, not on the enumerator
Collection itself doesn't need to implement MoveNext and Current, the enumerator does
When you implement GetEnumerator() like IEnumerator<T> with yield statements, MoveNext and Current are implemented automatically, parameter type T shouldn't be exactly MyClass
Documentation on CS1579:
To iterate through a collection using the foreach statement, the
collection must meet the following requirements:
Its type must include a public parameterless GetEnumerator method whose return type is either class, struct, or interface type.
The return type of the GetEnumerator method must contain a public property named Current and a public parameterless method named
MoveNext whose return type is Boolean.
This is the example of simple collection of numbers from 1 to 5:
class MyCollection
{
public IEnumerator<int> GetEnumerator()
{
for (int index = 1; index <= 5; index++) {
yield return index;
}
}
}
And now you can iterate through it using foreach:
var collection = new MyCollection();
foreach(var element in collection) {
Console.Write(element);
}
I am making collection, implementing IEnumerable explicitly and trying to iterate it from within:
public class MyCollection<T> : IEnumerable<T>, IEnumerable
{
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
IEnumerator<T> GetEnumerator() { yield return default(T); } // test
public void Test()
{
foreach (var item in this) { } // here is warning
}
}
I get compiler warning at this:
Warning CS0279 'MyCollection' does not implement the 'collection' pattern. 'MyCollection.GetEnumerator()' is either static or not public.
Hell yes, it's not public. Why it should be? I can make it public, but it's not needed for foreach outside of type:
foreach (var item in new MyCollection<string>()) { } // no warning
Am I doing something wrong?
The warning exists because the C# compiler can handle foreach in a number of different ways. One of those ways is to find a GetEnumerator method with a suitable return type. That's checked before the compiler checks whether or not the type of the expression implements IEnumerable or IEnumerable<T>.
In your case, it gets as far as finding the single parameterless GetEnumerator method, but it's not public. The C# specification recommends a warning at this point, as you may well have intended it to be usable for foreach. From the C# 5 spec, section 8.8.4, emphasis mine:
Perform overload resolution using the resulting method group and an empty argument list. If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, check for an enumerable interface as described below. It is recommended that a warning be issued if overload resolution produces anything except an unambiguous public instance method or no applicable methods.
Any of the following would solve the problem:
Rename GetEnumerator to GetEnumeratorImpl or similar:
IEnumerator IEnumerable.GetEnumerator() => GetEnumeratorImpl();
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumeratorImpl();
IEnumerator<T> GetEnumeratorImpl() { yield return default(T); }
Don't use explicit interface implementation for IEnumerable<T>.GetEnumerator() - put the implementation there
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<T> GetEnumerator() => { yield return default(T); }
Put the implementation in IEnumerable<T>.GetEnumerator, but cast this to IEnumerable<T> in IEnumerable.GetEnumerator to call it:
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<T>) this).GetEnumerator();
IEnumerator<T> IEnumerable<T>.GetEnumerator() => { yield return default(T); }
See the explanation for compiler warning CS0279 here: https://msdn.microsoft.com/en-us/library/bz2286x8(v=vs.90).aspx
There are several statements in C# that rely on defined patterns, such
as foreach and using. For example, foreach relies on the collection
class implementing the enumerable pattern. This error occurs when the
compiler is unable to make the match due to a method being declared
static or not public. Methods in patterns are required to be instances
of classes, and to be public.
(emphasis mine)
In visual studio 2015, when I go to List.cs and see class declaration, I see only one method named GetEnumerator:
public Enumerator GetEnumerator();
On the other hand, the interface IEnumerable<T> and IEnumerable specifies that it must define method whose format is:
IEnumerator<T> GetEnumerator();
IEnumerator GetEnumerator();
This made me believe that interface method can be implemented even though the reuturn type does not excatly match. Although, that turned out to be wrong when I tried.
What is happening here?
If you look at the source you will see two different GetEnumerator methods:
public Enumerator GetEnumerator() {
return new Enumerator(this);
}
IEnumerator<T> IEnumerable<T>.GetEnumerator() {
return new Enumerator(this);
}
The second one is only used if you are accessing the object through the IEnumerator interface. They both do use the same underlying implementation however.
[Serializable]
public struct Enumerator : IEnumerator<T>, System.Collections.IEnumerator
{
...
}
You can still get to the strongly typed version as follows:
var exampleList = new List<string>();
var enumerator1 = ((IEnumerable<string>)exampleList).GetEnumerator()
var enumerator2 = (IEnumerable<string>) exampleList.GetEnumerator()
For enumerator1 you are casting the list to use the GetEnumerator() method for the IEnumerable interface. For enumerator2 you are relying on the fact that the same implementation is used in in each and therefore you can just cast the enumerator.
The interface is implemented explicitly. The method you're seeing is not the interface implementation, it's a separate method for the class.
I am pretty new in C# (I came from Java) and I have a doubt about the use of:
I have this class:
namespace DataModel.MaliciousCode
{
public class PagedMalicious : Shared.Paged
{
public IEnumerable<MaliciousSmall> MaliciousCode { get; set; }
}
}
As you can see this class contains only a IEnumerable<MaliciousSmall> MaliciousCode
Reading the online documentation it seems to me to understand that IEnumerable is an interface that give me an iterator on a non generic collection.
What exactly means the previous assertion?
I have MaliciousSmall that is the type of a model object in my application (an object that contains some properties that map the fields of a table on the DB)
So my doubt are:
IEnumerable<MaliciousSmall> MaliciousCode: MaliciousCode is an iterable collection of MaliciousSmall objects? So it means that it represent a collection and some provided methods to iterate on it?
If the previous assertion is true, ok MaliciousCode object is an iterable collection but IEnumerable is an interface so who implement the method to iterate on this collection (coming from Java I think that an interface is not provided of implemented methods)
Some one can help me to understand these things?
Tnx
Andrea
IEnumerable<MaliciousSmall> MaliciousCode: MaliciousCode is an iterable collection of MaliciousSmall objects? So it means that it represent a collection and some provided methods to iterate on it?
Sort of - IEnumerable<T> provides one method - GetEnumerator - which returns an IEnumerator<T>. THAT interface allows you to iterate over the collection. Pre-Linq all IEnumerable allowed you to do was use the collection in a foreach loop (or use the provided IEnumerator directly, which is rare). Linq has since defined extension methods on IEumerable<T> that allow more sophisticated queries like Select, Where, Count, etc.
If the previous assertion is true, ok MaliciousCode object is an iterable collection but IEnumerable is an interface so who implement the method to iterate on this collection (coming from Java I think that an interface is not provided of implemented methods)
Typically the implementation is provided by using an underlying collection type like List<MaliciousSmall> or MaliciousSmall[]. So the IEnumerable implementation is provided by that class. The yield keyword introduced in C# 2.0 allows you to "return" an IEnumerable<T> and let the compiler provide the actual implementation.
So in your class, you might internally implement the collection as a List<T>:
public class PagedMalicious : Shared.Paged
{
public IEnumerable<MaliciousSmall> MaliciousCode { get; set; }
public PagedMalicious()
{
MaliciousCode = new List<MaliciousSmall>();
}
// other private methods that add to MaliciousCode
}
The use of IEnumerable<T> allows you to change the internal implementation without changing the public interface.
Your property MaliciousCode, represents an object of a class that implements IEnumerable<T> interface. On it's own, IEnumerable does not really mean anything. It just provides a structure. It is user's responsibility to implement the methods that are provided with interface whatever way the see it suitable.
Edit: Here is a simple example to demonstrate:
private void Form3_Load(object sender, EventArgs e)
{
Parent parent = new Parent();
parent.Child = new List<Child>(); // -> this is where implementer is decided.
//Before this line, Child property is not instantiated and is not referring to any object.
}
public class Parent
{
public IEnumerable<Child> Child { get; set; }
}
public class Child
{
public int MyProperty { get; set; }
}
To your doubts:
Yes and Yes
The interface itself can't implement anything, but you can assign an array of MaliciousSmall or a List<MaliciousSmall>. Both of them implement IEnumerable<MaliciousSmall>
IEnumerable<T> is the equivalent of Java's Iterable<T>. Since the early versions of C# did not have generics, IEnumerable was the only iterator available at that time. You can think of it as a kind of IEnumerable<object>.
Most generic collection types implement IEnumerable<T>, including arrays. The generic variant requires the non-generic variant to be implemented, therefore most collections (generic or not) implement IEnumerable.
However, these iterators are not limited to represent collections. They provide methods that allow you to enumerate items and these methods can generate items algorithmically as well. For instance an - in theory - endless enumeration of square numbers could be provided by an enumeration without the requirement to store those numbers anywhere.
In your case the IEnumerable<MaliciousSmall> MaliciousCode property could yield MaliciousSmall objects from the DB one by one as the enumeration is being enumerated without storing them in a collection object first.
Implementing IEnumerable<T> yourself requires the implementation of the IEnumerator<T> GetEnumerator() method. It returns an enumerator object which requires the implementation of the methods bool MoveNext(), void Dispose(), void Reset() and the property T Current { get; }.
You can implement these interfaces the good old way, by writing a lot of code, or you can use C#'s iterators. Iterators use a lot of compiler magic to create enumerables and enumerators automatically behind the scenes. See: Iterators (C# and Visual Basic).
As an example of C# iterators, let's implement your example with them (I dropped the setter as it stands in the way here):
public class PagedMalicious : Shared.Paged
{
public IEnumerable<MaliciousSmall> MaliciousCode
{
get
{
using (var conn = new SqlConnection("<my server connection>")) {
var cmd = new SqlCommand("SELECT name, number FROM myTable", conn);
conn.Open();
using (var reader = cmd.ExecuteReader()) {
while (reader.Read()) {
var maliciousSmall = new MaliciousSmall {
Name = reader.GetString(0),
Number = reader.GetInt32(1)
};
yield return maliciousSmall;
}
}
}
}
}
}
Each time yield return is executed, the control is passed back to the caller and he gets the next item. The state of the getter method is kept intact and its execution is halted here until the caller continues iterating and requires the next item. When he does so, the execution resumes just after the yield return statement.
You can see from this example, that enumerations are evaluated in a lazy way. The following code sums up the numbers of the whole table. The items are never stored in a collection; they are retrieved from the DB and created as they are enumerated. This is an advantage, if you have one million records! (You would use an SQL SUM aggregate function in a productive piece of code, so.)
var pagedMalicious = new PagedMalicious();
int sum = 0;
foreach (MaliciousSmall item in pagedMalicious.MaliciousCode) {
sum += item.Number;
}
I had to implement 2 interface same time with different generic parameter as below. I get confused enough about it. I had no idea which one of them iterate itself in foreach. Now i understand first one is implicitly choosen.
I have tried new BarList().GetEnumerator() but i can not specify type parameter on method level.
Only solution i have found it that casting it to interface like(new BarList() as IEnumerable<string>)
After confusing about it enough. I just wanted to know that this design is not really good idea ? I have to avoid to implement same generic interface one more time ?
class Program
{
static void Main(string[] args)
{
foreach (var item in new BarList())
{
}
}
}
class BarList: IEnumerable<string>, IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
throw new NotImplementedException();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
throw new NotImplementedException();
}
}
Edit:
Let me explain why i am going in this way.
I had to Implement IPagedList<T> interface which is inherited from IList<T>. I wanted to write extension method which convert it to My view model. like below
GetAll().ToPagedList(pageindex);//which is returning IPagedList Then i wanted to use it like below;
GetAll().ToPagedList(pageindex).ToViewModel<T,TViewModel>();
For achieve this I tried to return IPagedList<ViewModel> by that extension method.In that case I have to implement IPagedList 2 times with different parameter. But this strategy made confusing things. This is reason of it.
This seems a bit confusing. Why not make it explicit what is happening by adding the enumerators as properties rather than implementing them on the class. For example,
class ProductCollection
{
public IEnumerable<int> EnumerateTheInts { get { //code to produce enumerator }}
public IEnumerable<string> EnumerateTheStringss { get { //code to produce enumerator }}
}
It isn't always bad to implement an open generic interface twice on an object. For example, IHandle could be implemented by a class which can handle two types of T. However, I would find it confusing to implement IEnumerable twice, because you might not enumerate the type you expect in a for-each or in LINQ. Same reasoning for implementing more than one indexer incidentally. The type of your indexer will determine your result, which I can testify to being extremely confusing!
The compiler is picking the IEnumerator<int> GetEnumerator method by following the rules in 8.8.4 of the C# language specification which first looks for an accessible GetEnumerator() method on the BarList type. The only one of those which is available is the one returning IEnumerator<int>.
If you had made that method use explicit interface implementation as well, then it would have gone onto the later stages of section 8.8.4, which states that if there is more than one type T such that there is an implicit conversion from the expression type (BarList here) to IEnumerable<T> then an error is produced.
I would say this is a confusing design - I would probably add properties or methods to retrieve appropriate "views" on the data.
I'd avoid it. However, it depends on your usage.
It will be okay if you just wanted to pass the instance into a function that expects a IEnumerable<string> parameter explicitely:
you won't have to cast
the function won't even 'see' the other interfaces implemented, so there isn't any confusion.
YMMV
Your current design is confusing. While you have not provided any information about the nature of the collection itself, from the name, I can assume you are supposed to iterate over a bunch of products. Perhaps, you should simply have a class of type Product with a string property and an int property and simply return an IEnumerable<Product> instead.
This way, with LINQ extension methods, you can compose the IEnumerable<T> object you actually mean with:
collection.Select(product => product.IntegerProperty)
collection.Select(product => product.StringProperty)
Of course, you can provide helper methods inside the object as well:
class ProductCollection : IEnumerable<Product> {
public IEnumerable<Product> GetEnumerator() {
// ... return Product objects here.
}
public IEnumerable<int> AsIntegerCollection() {
// yield the integer collection here
}
public IEnumerable<string> AsStringCollection() {
// yield the string collection here
}
}
What are these collections of string and ints? I suppose they mean something in relation with the Product (for example Name, Id, etc...) so I would rather do something like this:
class ProductCollection : IEnumerable<Product>
{
public IEnumerator<Product> GetEnumerator()
{
...
}
public IEnumerator<string> ProductNames // a helper to enumerate product names
{
...
}
public IEnumerator<int> ProductIds // a helper to enumerate product ids
{
...
}
}