Warning - does not implement the 'collection' pattern - c#

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)

Related

The operand of yield return in c#

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.

List GetEnumerator return type does not match interface

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.

Implementing IEnumerable with an Array

This is likely a simple syntax question, but I can't figure it out.
Normally, I would do this:
public class OrderBook : IEnumerable<PriceLevel>
{
private readonly List<PriceLevel> PriceLevels = new List<PriceLevel>();
public IEnumerator<PriceLevel> GetEnumerator()
{
return PriceLevels.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return PriceLevels.GetEnumerator();
}
}
But instead of a list, I want to use an array - like this:
public class ArrayOrderBook : IEnumerable<PriceLevel>
{
private PriceLevel[] PriceLevels = new PriceLevel[500];
public IEnumerator<PriceLevel> GetEnumerator()
{
return PriceLevels.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return PriceLevels.GetEnumerator();
}
}
The IEnumerator IEnumerable.GetEnumerator() seems to compile fine - but the public IEnumerator<PriceLevel> says that I need some kind of cast - what is the best way of doing this?
William
Try this:
public class ArrayOrderBook : IEnumerable<PriceLevel>
{
private PriceLevel[] PriceLevels = new PriceLevel[500];
public IEnumerator<PriceLevel> GetEnumerator()
{
return PriceLevels.AsEnumerable().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return PriceLevels.GetEnumerator();
}
}
As you can see from your own IEnumerable<T> implementation, you need to provide both a generic and non-generic version of the method to fulfill the interface. In order to do this, since the methods have the same signature, one of them needs to be an explicit interface implementation. In the case of List, the generic version is a method in the class and the non-generic version is an explicit interface definition, since the generic version is generally more useful. In the case of an array, it already had the non-generic version as the implementation, and it was adding the generic version of the method in a subsequent version. To avoid the breaking change, the generic version is the explicit interface definition instead.
There are a number of ways of solving this issue. Here are three simple ones.
public IEnumerator<PriceLevel> GetEnumerator()
{
return PriceLevels.AsEnumerable().GetEnumerator();
}
public IEnumerator<PriceLevel> GetEnumerator()
{
IEnumerable<PriceLevel> enumerator = PriceLevels;
return enumerator.GetEnumerator();
}
public IEnumerator<PriceLevel> GetEnumerator()
{
return ((IEnumerable<PriceLevel>)PriceLevels).GetEnumerator()
}
Cast T[] to the corresponding IEnumerable<T>:
public IEnumerator<PriceLevel> GetEnumerator()
{
return ((IEnumerable<PriceLevel>)PriceLevels).GetEnumerator();
}
According to ECMA-335 Partition I, ยง8.9.1, a vector type (single dimension array like T[]) implements IList<T> which implies that it also implements IEnumerable<T>. However the implementation of the methods is explicit, so you'd need to use one of these:
Option 1: Simply use the implicit assignment of arrays to IList<T>.
private IList<PriceLevel> PriceLevels = new PriceLevel[500];
Option 2: Leave the member variable as an array, and use the AsEnumerable extension method. This extension method uses a supported implicit assignment which is preferable to using a direct cast like (IEnumerable<PriceLevel>)PriceLevels.
IEnumerator IEnumerable.GetEnumerator()
{
return PriceLevels.AsEnumerable().GetEnumerator();
}
Items to avoid:
The Cast<T> method introduces an unnecessary type check for each element of your array and should be avoided.
If you need to only include non-null elements from the enumeration, it's OK to use the OfType<T> extension method. Otherwise, this method also introduces an unnecessary type check on each element.

Implement same Generic Interface 2 times with different Generic parameter

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
{
...
}
}

Is it possible to implement several IEnumerable<T> in one class?

I want to do something like this:
class T : IEnumerable<string>, IEnumerable<int>
{
string [] _strings = new string [20];
int[] _ints = new int[20];
public T() { }
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
foreach (string str in _strings)
yield return str;
}
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
foreach (int i in _ints)
yield return i;
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
//Using in code:
T t = new T();
foreach (int i in t)
//to do something
foreach (string str in t)
//to do stuff
I desire to know Is there a way to realize It or not. May be there are tricks ?
You've nearly managed to implement both interfaces - you just need to change the non-generic implementation to show which generic implementation you're trying to delegate to. For example:
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<int>)this).GetEnumerator();
}
However, because you're implementing more than one IEnumerable<T> interface you'll need to cast in the foreach loop to show which one to use:
T t = new T();
foreach (int i in (IEnumerable<int>) t)
//to do something
foreach (string str in (IEnumerable<string>) t)
Personally I would strongly advise against doing this if possible though - it'll cause a lot of confusion for people reading your code.
See section 8.8.4 of the C# language specification for details of how the compiler treats the expression to iterate over in a foreach loop.
(By using "normal" interface implementation for one of the interfaces you could provide a sort of "default" - but I don't think that would really make it any better.)
I would suggest defining some struct types whose only field is an instance of your class type, initialized by the stuct's constructor, whose only public member would be GetEnumerator, and which implements IEnumerable<whatever> by calling an appropriate method on your base type. Then have your root class implement a member that returns a new instance of an appropriate struct.
For example, if your class Foo had a GetStringEnumerator method which returned a type that implements IEnumerable<String>, you could have Foo.AsStrings return a struct FooStringEnumerable whose GetEnumerator method called Foo.GetStringEnumerator.
Note that by having your enumerable thing be a struct rather than a class, you would avoid having to create an extra object instance in the common case where it is used in a "for-each" loop, since both vb and c# would duck-type the GetEnumerator method instead of casting to IEnumerable or IEnumerable<T>.

Categories

Resources