ienumerable vs list<T> - c#

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>

Related

IList, ICollection or IEnumerable in service interface?

I'm building a service for accessing my database with Entity Framework in ASP.NET MVC 5.
So I'm writing first a base service with his interface. But I'm worry about a little thing.
Usually I return an IEnumerable<T> in my interface, but that often leads to ToList() calls in the code.
So I was wondering what is the best to return in such an interface.
I could just return IList but I'm afraid that it may be too much and that I won't need all of the methods provided with IList.
Here's my code :
public interface IBaseService<T>
{
T Add(T obj);
T Update(T obj);
T Remove(string id);
T Get(string id);
ICollection<T> Find(Expression<Func<bool, T>> func);
ICollection<T> GetAll();
}
You said that
Usually I return an IEnumerable in my interface, but that often
leads to ToList() calls in the code.
You have to find out why you are calling ToList() on the results. It's possible, but unlikely, that you want to modify the result (add\remove items). It's generally not a good practice to return modifiable collection from methods like Find or GetAll, but you can return ICollection<T> or IList<T> (if you also need fast access via indexer or to insert\remove at specific positions).
However much more likely that you call to ToList to figure out how many elements are there and\or to access specific elements. If you need just Count - return IReadOnlyCollection<T> which extends IEnumerable<T> with just Count property. If you also need fast access via indexer - return IReadOnlyList<T> which extends IReadOnlyCollection<T> with indexer.
Both Array and List<T> implement all those interfaces so you can just return those classes as is:
static IReadOnlyList<string> Test() {
return new string[0]; // fine
}
However, when returning List this way - caller might cast it back to IList<T> and still modify it. That's not a problem usually, but if you want to prevent that, use AsReadOnly on list (it will not copy anything to the new list so don't worry about perfomance):
static IReadOnlyList<string> Test() {
return new List<string>().AsReadOnly(); // not required but good practice
}
It depends on your intention. In most cases your return type should probably be IReadOnlyCollection<T>. In rare cases where you want the caller to be able to modify the collection, you can return ICollection<T>. Use IEnumerable<T> only if you are certain that the caller will only require forward iteration.
I guess the purest solution would be to go with IEnumerable<T>, but it comes down to setting a convention in your solution. If you're responsible for architecture, you might as well decide to return List<T> just to have the comfort of broader set of methods at hand.

Stop other classes from adding to lists with "private set;"

Currently, I have a class (classB) that has a list --v
class classB
{
public List<int> alist { get; private set; }
...
And I can accessing this class from another class (classA)
ClassB foo = new ClassB();
foo.alist.Add(5);
Question is, can I stop this from happening? (make it unchangeable from other classes) Thanks!
Just expose the IReadOnlyList<T> interface:
private List<int> alist;
public IReadOnlyList<int> Alist
{
get { return this.alist; }
}
From inside of the class, you continue to use "alist", to add/remove elements. From outside of the class you can only access "Alist", which doesn't allow to modify the collection (unless explicitly cast).
Well, there are various options here.
You could change the property type to one which only provides a read-only interface (e.g. IReadOnlyList<T> or IEnumerable<T>. That doesn't stop the caller from casting the returned reference back to List<T> though.
You could create a ReadOnlyCollection<T> to wrap your real list, and only expose that - that wrapper will prevent the caller from being able to access the real list at all (other than by reflection)
If your code doesn't need to modify the collection either, you could just keep the ReadOnlyCollection<T> wrapper, or use the immutable collections package
You could avoid exposing the list at all, perhaps implementing IEnumerable<T> within your class
It really depends on exactly what your requirements are.

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

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.

Adding IEnumerable<T> to class derived from CollectionBase

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.

Categories

Resources