How to make the class as an IEnumerable in C#? - c#

So I've got a class and a generic List inside of it, but it is private.
class Contacts
{
List<Contact> contacts;
...
}
I want to make the class work as this would do:
foreach(Contact in contacts) .... ;
like this (not working):
Contacts c;
foreach(Contact in c) .... ;
In the example above the Contact class instance c has to yield return every item from contacts(private member of c)
How do I do it? I know it has to be IEnumerable with yield return, but where to declare that?

Implement the interface IEnumerable:
class Contacts : IEnumerable<Contact>
{
List<Contact> contacts;
#region Implementation of IEnumerable
public IEnumerator<Contact> GetEnumerator()
{
return contacts.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}

Or return an IEnumerator<Contact> by providing a GetEnumerator method:
class Contacts
{
List<Contact> contacts;
public IEnumerator<Contact> GetEnumerator()
{
foreach (var contact in contacts)
yield return contact;
}
}
The foreach looks for GetEnumerator. Have a look here for the language specification details regarding this: https://stackoverflow.com/a/3679993/284240
How to make a Visual C# class usable in a foreach statement

public class Contacts: IEnumerable
{
......
public IEnumerator GetEnumerator()
{
return contacts.GetEnumerator();
}
}
Should do a trick for you.

class Program
{
static void Main(string[] args)
{
var list = new Contacts();
var a = new Contact() { Name = "a" };
var b = new Contact() { Name = "b" };
var c = new Contact() { Name = "c" };
var d = new Contact() { Name = "d" };
list.ContactList = new List<Contact>();
list.ContactList.Add(a);
list.ContactList.Add(b);
list.ContactList.Add(c);
list.ContactList.Add(d);
foreach (var i in list)
{
Console.WriteLine(i.Name);
}
}
}
class Contacts : IEnumerable<Contact>
{
public List<Contact> ContactList { get; set; }
public IEnumerator<Contact> GetEnumerator()
{
return ContactList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ContactList.GetEnumerator();
}
}
class Contact
{
public string Name { get; set; }
}

How about just extending List<Contact>
If you don't want to extend any other class its a very simple, fast option:
class Contacts :List<Contact>
{
}

Related

Using LINQ: How To Return Array Of Properties from a Class Collection?

Here is a Basic Class with TheProperty in question:
class BasicClass {
public BasicClass() {
TheProperty = new Object();
Stamped = DateTime.Now;
}
public object TheProperty { get; set; }
public DateTime Stamped { get; private set; }
}
Here is the Basic List:
class BasicList {
private List<BasicClass> list;
public BasicList() {
list = new List<BasicClass>();
}
public BasicClass this[object obj] {
get { return list.SingleOrDefault(o => o.TheProperty == obj); }
}
public void Add(BasicClass item) {
if (!Contains(item.TheProperty)) {
list.Add(item);
}
}
public bool Contains(object obj) {
return list.Any(o => o.TheProperty == obj); // Picked this little gem up yesterday!
}
public int Count { get { return list.Count; } }
}
I'd like to add a class to BasicList that will return an array of items.
I could write it like this, using traditional C#:
public object[] Properties() {
var props = new List<Object>(list.Count);
foreach (var item in list) {
props.Add(item.TheProperty);
}
return props.ToArray();
}
...but how would I write that using a LINQ or Lambda query?
return list.Select(p=>p.TheProperty).ToArray()

How to use foreach on a list of lists that on another class

public class ItemCollection
{
List<AbstractItem> LibCollection;
public ItemCollection()
{
LibCollection = new List<AbstractItem>();
}
public List<AbstractItem> ListForSearch()
{
return LibCollection;
}
and in another class i wrote this:
public class Logic
{
ItemCollection ITC;
List<AbstractItem> List;
public Logic()
{
ITC = new ItemCollection();
List = ITC.ListForSearch();
}
public List<AbstractItem> search(string TheBookYouLookingFor)
{
foreach (var item in List)
{
//some code..
}
and the list in the foreach is contain nothing
and i need to work on this list (this list is should be the same content as libcollection) for the search method
If ItemCollection serves no purpose other than to own the List<AbstractItem>, then the class should probably be removed altogether and just use List<AbstractItem> instead.
If ItemCollection has another purpose and others shouldn't have access to the underlying List<AbstractItem>, it can implementIEnumerable<AbstractItem>:
class ItemCollection : IEnumerable<AbstractItem>
{
List<AbstractItem> LibCollection;
public ItemCollection() {
this.LibCollection = new List<AbstractItem>();
}
IEnumerator<AbstractItem> IEnumerable<AbstractItem>.GetEnumerator() {
return this.LibCollection.GetEnumerator();
}
IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return ((IEnumerable)this.LibCollection).GetEnumerator();
}
}
class Logic
{
ItemCollection ITC;
public Logic() {
ITC = new ItemCollection();
}
public List<AbstractItem> Search(string TheBookYouLookingFor) {
foreach (var item in this.ITC) {
// Do something useful
}
return null; // Do something useful, of course
}
}
Otherwise, you may want to expose LibCollection directly and let other code enumerate over that:
class ItemCollection
{
public List<AbstractItem> LibCollection { get; private set; }
public ItemCollection() {
this.LibCollection = new List<AbstractItem>();
}
}
class Logic
{
ItemCollection ITC;
public Logic() {
ITC = new ItemCollection();
}
public List<AbstractItem> Search(string TheBookYouLookingFor) {
foreach (var item in this.ITC.LibCollection) {
// Do something useful
}
return null; // Do something useful
}
}

Why I can not cast?

public abstrct class Item
{
public string Name {get;set;}
}
public class Music : Item
{
public double Price {get;set;}
}
public class Game : Item
{
public string Image {get;set;}
}
public class Inventory
{
private IList<Item> _games;
private IList<Item> _musics;
public Inventory()
{
_games = new List<Item>();
_musics = new List<Item>();
}
public void Add<T>(T item) where T : Item
{
if(typeof(T) == typeof(Game))
{
_game.add(item);
}
if(typeof(T) == typeof(Music))
{
_muisc.add(item);
}
public List<T> GetCollection<T>() where T : Item
{
return (List<T>) _muiscs;
}
class Porgram
{
static void Main(string[] args)
{
Inventory inventory = new Inventory();
var music1 = new Music(){ Name ="aa", Price = 10};
var Music2 = new Music() { Name ="bb", price = 20 };
inventory.add(music1);
inventory.add(music2);
List<Music> myMusics = inventory.GetCollection<Music>();
}
The code will compile but it will throw exception when try to Call Get Collection method.
I am not sure really why? I am guess i am using generic incorrect.
A List<Item> cannot be cast to a List<Music>. While Music is a subclass of Item, generic types do not follow the same inheritance pattern as their collection type. The simplest way to fix your code would be to replace the cast in your GetCollection method with a call to the Linq extension method cast, followed by ToList. That said, I think your entire class could be redesigned to handle this sort of inheritence better.
So, your GetCollection method looks like this:
public List<T> GetCollection<T>() where T : Item
{
return _musics.Cast<T>().ToList();
}
Try this code:
public abstract class Item
{
public string Name { get; set; }
}
public class Music : Item
{
public double Price { get; set; }
}
public class Game : Item
{
public string Image { get; set; }
}
public class Inventory<E> where E : Item
{
private IList<E> _games;
private IList<E> _musics;
public Inventory()
{
_games = new List<E>();
_musics = new List<E>();
}
public void Add(E item)
{
if (typeof(E) == typeof(Game))
{
_games.Add(item);
}
if (typeof(E) == typeof(Music))
{
_musics.Add(item);
}
}
public List<E> GetCollection()
{
return _musics;
}
}
public class Program
{
public static void Main(string[] args)
{
Inventory<Item> inventory = new Inventory<Item>();
var music1 = new Music() { Name = "aa", Price = 10 };
var music2 = new Music() { Name = "bb", Price = 20 };
inventory.Add(music1);
inventory.Add(music2);
List<Item> myMusics = inventory.GetCollection();
}
}
You need to declare your Inventory class to be generic where it takes in a class that extend Item
Also: It looks like you wrote the code, and didn't copy and paste it... I don't know why you did that...
Just modify your GetCollection method as
public List <T> GetCollection<T>() where T :Item
{
if (typeof(T) == typeof(Game))
{
return _games.Cast<T>().ToList();
}
if (typeof(T) == typeof(Music))
{
return _musics.Cast<T>().ToList(); ;
}
return null;
}

IEnumerable collection to List

I've written a CustomerCollection class, which implements the IEnumerable and IEnumerator interfaces. Now I want the CustomerCollection class object to be searchable by Where() And Find() function and also would like to get a List object of type Customer From the CustomerCollection class. Please help. Also, is the implementation of the interfaces right.
public class Customer
{
private int _CustomerID;
private string _CustomerName;
public Customer(int customerID)
{
this._CustomerID = customerID;
}
public int CustomerID
{
get
{
return _CustomerID;
}
set
{
_CustomerID = value;
}
}
public string CustomerName
{
get
{
return _CustomerName;
}
set
{
_CustomerName = value;
}
}
}
public class CustomerController
{
public ArrayList PopulateCustomer()
{
ArrayList Temp = new ArrayList();
Customer _Customer1 = new Customer(1);
Customer _Customer2 = new Customer(2);
_Customer1.CustomerName = "Soham Dasgupta";
_Customer2.CustomerName = "Bappa Sarkar";
Temp.Add(_Customer1);
Temp.Add(_Customer2);
return Temp;
}
}
public class CustomerCollection : IEnumerable, IEnumerator
{
ArrayList Customers = null;
IEnumerator CustomerEnum = null;
public CustomerCollection()
{
this.Customers = new CustomerController().PopulateCustomer();
this.CustomerEnum = Customers.GetEnumerator();
}
public void SortByName()
{
this.Reset();
}
public void SortByID()
{
this.Reset();
}
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)this;
}
public void Reset()
{
CustomerEnum.Reset();
}
public bool MoveNext()
{
return CustomerEnum.MoveNext();
}
public object Current
{
get
{
return (Customer)CustomerEnum.Current;
}
}
}
You can call Cast<Customer>() on your IEnumerable which will give you an IEnumerable<Customer>, or just implement IEnumerable<Customer> to begin with. LINQ is almost entirely hooked into IEnumerable<T>, not IEnumerable. Once you did that you'd get all the LINQ to objects goodness for free.
I recommend to use OfType<T>() instead of Cast<T>() because if your collection contains T1 and T2, collection.Cast<T1>() will throw an error while collection.OfType<T1>() will return IEnumerable<T1> contains only instances of T1 not T2
This will do what you want. Note, I have abstracted out the IEnumerable to make it reusable and reduced the complexity of all of the other classes.
//Write your Test first
public class Test
{
public void TestEnumerator()
{
var customers = new CustomerCollection();
var qry =
from c in customers
select c;
foreach (var c in qry)
{
Console.WriteLine(c.CustomerName);
}
//Create a new list from the collection:
var customerList = new List<Customer>(customers);
}
}
public abstract class MyColl<T> : IEnumerable<T>
{
protected T[] Items;
public IEnumerator<T> GetEnumerator()
{
foreach (T item in Items)
{
yield return item;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class Customer
{
public Customer(int customerID)
{
CustomerID = customerID;
}
public int CustomerID { get; set; }
public string CustomerName { get; set; }
}
public class CustomerController
{
public Customer[] PopulateCustomer() {
return new [] {new Customer(1) {CustomerName = "Soham Dasgupta"},
new Customer(2) {CustomerName = "Bappa Sarkar"}};
}
}
public class CustomerCollection : MyColl<Customer>
{
public CustomerCollection()
{
Items = new CustomerController().PopulateCustomer();
}
}
public class CustomerController
{
public List<Customer> PopulateCustomer()
{
List<Customer> Temp = new ArrayList();
Customer _Customer1 = new Customer(1);
Customer _Customer2 = new Customer(2);
_Customer1.CustomerName = "Soham Dasgupta";
_Customer2.CustomerName = "Bappa Sarkar";
Temp.Add(_Customer1);
Temp.Add(_Customer2);
return Temp;
}
}
public class CustomerCollection : List<Customer>
{
List<Customer> Customers = new List<Customer>();
public CustomerCollection()
{
this.Customers = new CustomerController().PopulateCustomer();
}
}
new List<Customer>(myCustomerEnumerator);
The recommended base class to use for creating your own collection implementations is System.Collections.ObjectModel.Collection<T>
(from MSDN)
This base class is provided to make it easier for implementers to create a custom collection. Implementers are encouraged to extend this base class instead of creating their own.
public class CustomerCollection : Collection<Customer>
{
}

C#: IEnumerable, GetEnumerator, a simple, simple example please!

Trying to create an uebersimple class that implements get enumerator, but failing madly due to lack of simple / non-functioning examples out there. All I want to do is create a wrapper around a data structure (in this case a list, but I might need a dictionary later) and add some functions.
public class Album
{
public readonly string Artist;
public readonly string Title;
public Album(string artist, string title)
{
Artist = artist;
Title = title;
}
}
public class AlbumList
{
private List<Album> Albums = new List<Album>;
public Count { get { return Albums.Count; } }
.....
//Somehow GetEnumerator here to return Album
}
Thanks!
You can simply return the enumerator returned by List<T>.GetEnumerator:
public class AlbumList : IEnumerable<Album>
{
// ...
public IEnumerator<Album> GetEnumerator()
{
return this.albums.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
In addition to the other answers if you need a little more control over how the enumerator works or if there is a requirement to customize it beyond what the underlying data structure can provide then you can use the yield keyword.
public class AlbumList : IEnumerable<Album>
{
public IEnumerator<Album> GetEnumerator()
{
foreach (Album item in internalStorage)
{
// You could use conditional checks or other statements here for a higher
// degree of control regarding what the enumerator returns.
yield return item;
}
}
}
using System.Collections;
using System.Collections.Generic;
public class AlbumList : IEnumerable<Album>
{
private List<Album> Albums = new List<Album>();
public int Count => Albums.Count;
public IEnumerator<Album> GetEnumerator()
{
return this.Albums.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
or the simplified version:
public class AlbumList
{
private List<Album> Albums = new List<Album>();
public int Count => Albums.Count;
public IEnumerator<Album> GetEnumerator()
{
return this.Albums.GetEnumerator();
}
}
I wouldn't advice leaving out the IEnumerable<T> interface, because you loose integration with .NET such as possibilities to use LINQ, but you can iterate over the collection using a foreach in C#.
Or this one is even shorter :-)
public class AlbumList : List<Album>
{
}
Of course this last one is a mutable list, which perhaps is not exactly what you want.
Based on your comment that you want to have a wrapper around a data structure (the list), and an enumerator function to return an Album, I think you're talking about indexer properties, right? This is how you do it:
public class Album
{
public readonly string Artist;
public readonly string Title;
public Album(string artist, string title)
{
Artist = artist;
Title = title;
}
}
public class AlbumList
{
private List<Album> Albums = new List<Album>();
public int Count
{
get { return Albums.Count; }
}
public Album this[int index]
{
get
{
return Albums[index];
}
}
public Album this[string albumName]
{
get
{
return Albums.FirstOrDefault(c => c.Title == albumName);
}
}
public void Add(Album album)
{
Albums.Add(album);
}
public void Remove(Album album)
{
Albums.Remove(album);
}
}
A small console program:
AlbumList albums = new AlbumList();
albums.Add(new Album { Artist = "artist1", Title = "title1" });
albums.Add(new Album { Artist = "artist2", Title = "title2" });
for (int i = 0; i < albums.Count; i++)
{
Console.WriteLine(albums[i].Artist);
Console.WriteLine(albums[i].Title);
}
Console.WriteLine("title for artist1");
Console.WriteLine(albums["artist1"].Title);

Categories

Resources