Adding IEnumerable<T> to class derived from CollectionBase - c#

Suppose I have a class TestCollection which is used to hold objects of type Test and is defined as
public class TestCollection : CollectionBase
This allows me to iterate through the collection either as
foreach(object o in collection)
...
or
foreach(Test t in collection)
but does not allow me to use new Linq queries.
If I change the definition of the class to
public class TestCollection : CollectionBase, IEnumerable<Test>
and add a method
public new IEnumerator<Test> GetEnumerator()
{
foreach (Test o in this.List)
yield return o ;
}
then linq queries are available.
However this new method is not just called for linq queries, but is also called in the legacy code (ie during the foreach(object o in collection) and foreach(Test in Collection).
Is there any difference between the old way of iterating through the collection and this new way assuming all the items in the collection are of type Test? I am aware that adding the IEnumerator method will cause the program to throw an exception if it finds any types other than Test, but want to know if I have overlooked anything.

Since you are in 2.0 (or above), perhaps just inherit from Collection<T>?
public class TestCollection : Collection<Test> {
// your extra code here
}
Then you get IList<T>, ICollection<T>, IEnumerable<T> for free, and virtual methods that you can override to put your stamp on the behaviour.

No, you will see identical results and only experience a single extra level of indirection (as the new GetEnumerator method simply calls the existing GetEnumerator method and streams its output).

The IEnumerator<T> compiled from an iterator doesn't implement the Reset method. EDIT: I mean that it will throw a NotImplementedException.
There's nothing actually wrong with that, but if you want the Reset method, you'll have to write your own iterator class, which isn't hard.

Related

Return a list of a subtype as a List of supertype in C#

I want to make "somehow" the following work:
public class GenericsTest<T> where T: ISomeInterface
{
private List<T> someList = new List<T>();
public List<ISomeInterface> GetList()
{
return someList; //of course this doesn't even compile
}
}
Is there a way to do this (like the wildcards in Java) and I just missed it? Or it just can't be done?
EDIT:
First of all thank you all for the interest and your answers/comments. Second, sure there are ways to do that, and probably the simplest and most performance effective (not sure for that though) is to create a new list of the proper type and iteratively add the elements of the other list (someList in our case). Question is with all those new variance things, the "ins" and the "outs" if there is a way to do it the "generics way". In Java that could be:
public class GenericsTest<T extends SomeInterface> {
private List<T> someList = new ArrayList<>();
public List<? extends SomeInterface> getList() {
return someList;
}
}
So I was wandering if there is the ? extends equivalent in C#. I could accept a "no" as a short answer, I just thought I should ask first.
EDIT 2:
Some users believe and some others insist that this is a duplicate of a question that has to do with casting. Since I marked the most suitable for me answer, for the sake of clarity I explain. Guys, I don't want to cast. I am simply looking for an equivalent of the Java wildcard with the extends constraint. Of course Java has compile time only generics, which might make the difference. If the equivalent in C# is done with casting fine, but I am aware of the problem of "having a Dog object in Cat list", so my question is different.
I believe this would do the trick:
public List<ISomeInterface> GetList()
{
return someList.Cast<ISomeInterface>().ToList();
}
You could also do:
public List<ISomeInterface> GetList()
{
return someList.OfType<ISomeInterface>().ToList();
}
The difference is that the first option will do a hard cast, which means that if one of the elements does not implement ISomeInterface an exception will be thrown. The second version will only return instances that implement ISomeInterface and will just skip over instances that don't.
In your example, you can safely use the Cast option as you are guaranteed that all instances implement ISomeInterface.
You can use OfType<T>
public class GenericsTest<T> where T : ISomeInterface
{
private List<T> someList = new List<T>();
public List<ISomeInterface> GetList()
{
return someList.OfType<ISomeInterface>().ToList();
}
}
In C#, generic variance works differently than in Java. If you want to take advantage of it, you need to work with an interface (or delegate) that's variant. Such interfaces include IEnumerable<T> and IReadOnlyList<T> (new in .Net 4.5), but not IList<T>, because that wouldn't be type-safe.
That means you can do something like this:
public class GenericsTest<T> where T: ISomeInterface
{
private List<T> someList = new List<T>();
public IEnumerable<ISomeInterface> GetList()
{
return (IEnumerable<ISomeInterface>)someList;
}
}
here is the problem. lets pretend that this code would compile:
class foo: ISomeInterface {}
class bar: ISomeInterface {}
GenericsTest<foo> testobject = GenericsTest<foo>();
List<ISomeinterface> alist = testobject.GetList();
Internally testobject really has a list of foo but by allowing us to cast to a List<ISomeinterface> there is no way for a caller to know that bad things are going to happen if we try to insert a bar into the list. This is the reason that it isn't allowed and cant easily be allowed.
The way to solve it is to either:
Use a List<ISomeInterface> internally (if the collection becoming heterogeneous is OK)
Create a copy of the list with the desired type if the list being read only is OK. If you need to able to mutate the list in some cases you can add type safe methods on the GenericTest class to accomplish that.
One major weakness in Java and .NET is that there is no distinction made between mutable-type references which are used to encapsulate the identity of a mutable object, from those which are used to encapsulate its state. In particular, if code calls getList and then attempts to modify the returned list, it's not clear whether such an attempt should modify the list which is held by GenericsTest<T>, or whether it should simply modify a copy of the list which was created by the method (leaving the original list alone). It's also unclear whether the list returned by getList should be affected by any future changes which are made to the set of items held by the GenericsList<T>.
If your goal is to allow a caller to have a new list which is populated with the items in the original list, but which it can manipulate as it sees fit, I would suggest that you either use an AsList method or else define an interface
interface ICopyableToNewList<out T> {
// List<T> ToList(); // Can't be an actual interace member--must use extension method
int Count {get;}
}
implement a ToList() extension method which acts on that interface:
public static List<T> ToList<T>(this ICopyableToNewList<T> src)
and have your class implement ICopyableToNewList<T>. Such a declaration will allow code to get a new list of any type which is a supertype of T by casting the GenericTest<T> to ICopyableToNewList<desiredType>.

ienumerable vs list<T>

It is said that IEnumerable is used in a custom collection. One of the uses is the foreach loop used to traverse through the custom collection.
However my question is that instead of making a custom collection that first implements IEnumerable and then constructing another class to implement IEnumerator to store a group of custom objects, why can't we just use list<your_customer_object>.
Thanks in advance for help.
Because you might want to implement a different data structure. IEnumerable abstracts the concept of sequence, while a List has the concept of index, adding/removing items and its own, data structure.
As an example of different structure, here's a class which allows you to enter an infinite foreach loop.
public class InfiniteSequence : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
return new InfiniteEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
class InfiniteEnumerator : IEnumerator<int>
{
public void Dispose()
{
throw new NotImplementedException();
}
public bool MoveNext()
{
Current++;
return true;
}
public void Reset()
{
Current = 0;
}
public int Current { get; private set; }
object IEnumerator.Current
{
get { return Current; }
}
}
}
Of course you can use List<T>.
If List<T> fits your needs, then use it and don't create a new class that inherits from IEnumerable<T>.
You would provide your own implementation of IEnumerable<T> when List<T> isn't right for your needs. The canonical example of this is when you want to support lazy evaluation of your collection, perhaps with a method that uses yield return.
As #ken2k said, you can just List<T> and you will got a generic version of List with your T type. But if you want to hide this implementation and customize some operations that List<T> or include new features, you can inherits from the List and implement your own methods. For sample:
public class CustomerCollection : List<Customer> // at this time, you have all methods from List such as Add, Remove, [index] etc...
{
public double AverageAge()
{
return this.Average(customer => customer.Age)
}
// other methods...
}
IEnumeralbe is the most abstraction of collections in .Net Framework, you can just interate in this abstraction.
You can just use List<T> or any other of the generic collection types. After all List<T> implements IEnumerable<T>.
Do you have a particular edge case that you need to cover with a bespoke collection?
Of course you can define your members as List<T>, that however binds the customer of your class to a specific implementation. If you define the member as IEnumerable<T> (assuming that the consumers will only want to enumerate your collection) than you can change the implementation to a different collection type that implements the interface without breaking the contract. You if you change it from List<T> to SortedSet<T> to implement order your consumers are not affected.
It's basically the advantage of coding against interfaces rather than concrete types.
You can use a different interface, ie. ICollection<T> if your consumers want more than just enumerate.
If it doesn't do anything else, go ahead. Specialized collections are for collections that need to do... special... things.
(For example, a ListViewItemCollection would have to notify its parent ListView when updated, so it needs to implement IList(T), and therefore IEnumerable(T). If you had a custom collection, it might inherit from that. Inheriting only from IEnumerable(T) makes sense only when your collection can be enumerated, but not indexed.)
You Can.
public class List<T> : IList<T>, ICollection<T>,
IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>,
IEnumerable
I think the source of confusion here is the difference between a "custom collection" and a "collection of custom class instances". Of these two, your List<CustomObject> is the latter case - you are only reusing a collection created by someone else and taking advantage of generics to keep the item type info, that's all. Truly custom collection would probably implement IEnumerable<T>, but you will rarely (if ever) need it.
So in this case you not only can, but probably also should use List<CustomObject>

When should you use IEnumerable and GetEnumerator?

In many of our projects I have seen a few custom collection / or container classes that hold a some sort of generic collection, e.g. a List(of T) class.
They usually have a GetXXX method that returns a IEnumerable of whatever type the custom collection class uses so the internal collection can be iterated around using a foreach loop.
e.g.
public IEnumerable<UploadState> GetStates
{
get
{
return new List<UploadState>(m_states);
}
}
My question is that should these classes instead implement the IEnumerable interface, and call GetEnumerator on the List itself.
Is there a preferred way, or is it up to the developer?
If your class is a custom collection class then yes, it should implement IEnumerable<T>. In this case a public property for the inner list would be redundant. Imagine a simple class:
public class People : IEnumerable<Person>
{
List<Person> persons = new List<Person>();
public IEnumerator<Person> GetEnumerator()
{
return persons.GetEnumerator();
}
}
But if your class cannot act like a collection then provide a public IEnumerable property for its elements:
public class Flight
{
List<Person> passengers = new List<Person>();
public IEnumerable<Person> Passengers
{
get { return passengers; }
}
}
Anyway, it's always up to the developer to choose the right design.
I would do it that way:
public IEnumerable<UploadState> GetStates
{
get
{
foreach (var state in m_states) {
yield return state;
}
}
}
It is cleaner, your users don't get a list where they shouldn't (they could cast it to a List<T>after all) and you don't need to create a List<T>object.
EDIT: Misunderstood the question. I think if the class is meant to be a collection, it should implement IEnumerable<T>.
Consider that in your code example a new list created. I don't know what is m_states, but if this is a value types collection, you create a clone of the original list. In this way the returning list can be manipulated form the caller Add/Remove/Update elements. without affectiing original data.
If m_states are reference types, this still creates a new list which can be again manipulated by the caller Add/Remove/ No update elements (it's a reference!) without affecting original data.
What about IEnumerable<T>, its just a way to make a returning type generic, and not make strong coupling to List<T> type.
I think if your newly implemented class just behaves the sameway as a list does, there is no need to implement it. If you need some kind of custom logic, it depends on what you want to do; you can inherit list or you can implement IEnumerable. It just depends what is to be achieved.
You might want to check this:
http://www.codeproject.com/Articles/4074/Using-IEnumerator-and-IEnumerable-in-the-NET-Frame
I didn't read fully it yet, but I think this answers your question.
You should be deriving your custom collection classes based on one of the classes in System.Collections.ObjectModel namespace. They already contain implementations of IEnumerable<T> and the non generic IEnumerable interfaces.

Can we use GetEnumerator() without using IEnumerable interface?

I have a class called Primes and this class implements GetEnumerator() without implementing IEnumerable interface.
public class Primes
{
private long min;
private long max;
public Primes()
: this(2, 100)
{
}
public IEnumerator GetEnumerator()
{...}
I don't get it. Am I missing something?
Firstly, as others have said you can introduce your own methods without implementing interfaces anyway - you can write your own Dispose method without implementing IDisposable etc. For well-known interfaces I'd suggest this is almost a bad idea (as readers will have certain expectations) but it's entirely valid.
More importantly though, the foreach statement in C# can work without IEnumerable being involved. The compiler effectively does compile-time duck typing on the names GetEnumerator(), Current and MoveNext(). This was primarily to allow strongly-typed (and non-boxing) iteration in C# 1, before generics. See section 8.8.4 of the C# 3 spec for more details.
However, it's generally a bad idea to do this now if you do want to be able to easily iterate over the contents of an instance as a collection - and indeed I'd suggest implementing IEnumerable<T> instead of just IEnumerable.
yes you can. even you can use it in foreach. The only problem that objects of this class can't be cast to IEnumerable although they implement needed method.
There's no reason that you have to implement IEnumerable in order to create a function called GetEnumerator that returns an IEnumerator, that just means that you won't be able to supply an instance of that type to something that expects an IEnumerable.
an interface ensures a contract, that does not mean that you can't have a method with the same signature as one in the interface on a class that does not impliment the interface.

Calling IEnumerator from an Interface class

I am new to enumerating collections so forgive if this question sounds silly.
I have an class
public class PersonStuff : IPersonStuff, IEnumerable<User>
{
Person person = new Person();
...
IEnumerator<Person> IEnumerable<Person>.GetEnumerator()
{
return (person as IEnumerable<Person>).GetEnumerator();
}
}
As you can see, I am implementing two interfaces in the above: one being IPersonStuff and the other being IEnumerable.
The Person class is a simple getter/setter each type being of string e.g. name, address except dateofbirth which is DateTime.
And in my IPersonStuff I have this:
interface IPersonStuff
{
...
IEnumerator<Person> IEnumerable<Person>.GetEnumerator();
}
Once working, I would like to call it in the following manner (from any class):
IPersonStuff personStuff = new PersonStuff();
foreach (Person u in personStuff)
{
//this loop should iterate thru the elements.
}
However, I get the following error:
'IEnumerable<...>.GetEnumerator': explicit interface declaration can only be declared in a class or struct
Basically I want to know how is it possible to call the IEnumerator IEnumerable.GetEnumerator() I have in the PersonStuff class through the IPersonStuff Interface.
Is IPersonStuff itself collection-like, or just a bunch of properties? If it's not collection-like, there's no need to make it enumerable.
I believe the error is due to using System.Collections.Generic but not System.Collections -- the non-generic IEnumerable is thus not in scope.
I think that if you want IPersonStuff to be enumerable then you can just have IPersonStuff inherit IEnumerable<T> (which in turn inherits IEnumerable). Otherwise, I don't think you'll be able to use foreach over a reference to IPersonStuff.
EDIT Based on further comments and edits, it looks like PersonStuff is intended to be a collection-like data access class for Person, with instantiation managed in monostate fashion.
The monostate instantiation defeats the point of defining an interface IPersonStuff: if you always create it with new PersonStuff() in-line, then (bar bytecode postprocessing) there is no opportunity to use some non-default implementation of the interface.
I would suggest defining some sort of data access context object with properties representing each of your global entity collections, then pass that around in your choice of fashion -- using a parameter or accessor-based singleton is preferable to a monostate. This object may then wrap a database connection, NHibernate session, or similar.
You're getting the error most probably because like what Jeffrey said you're missing a reference to System.Collections.Generic which has the non-generic IEnumerable. Once you have the correct reference you won't need the cast of (person as IEnumerable).
On whether it should/can be type safe depends on your situation. If all elements of what you're enumerating through are of the same type (i.e. fixed class, interface or subclass) that you should/can use the type safe IEnumerable. But if say maybe you want to enumerate all the properties in Person (which sounds like what you might be attempting) and you're returning diff types then you'll have to use the non-generic IEnumerable.
If you are enumerating through the properties of your class then one nice trick is to use yield return for each property (instead of writing a custom class that implements IEnumerator) in Person.GetEnumerator();

Categories

Resources