2010-08-24 5 views
4

J'ai écrit une classe CustomerCollection, qui implémente les interfaces IEnumerable et IEnumerator. Maintenant, je veux que l'objet de classe CustomerCollection puisse être recherché par la fonction Where() et Find() et souhaite également obtenir un objet List de type Customer de la classe CustomerCollection. S'il vous plaît aider. Aussi, est la mise en œuvre des interfaces correctes.IEnumerable collection to List

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; 
     } 
    } 

} 
+1

Vos classes de collection ne devraient jamais mettre en œuvre IEnumerable ** et ** IEnumerator (sauf pour les rares cas où il n'y a que jamais aucun élément). Les énumérateurs sont dynamiques et les énumératifs ne le sont pas. Votre code ne fonctionnera pas lorsque GetEnumerator() est appelé plusieurs fois. –

+0

Voulez-vous dire 'IEnumerable '/'Liste ' ou exactement 'IEnumerable' /' List'? – abatishchev

+3

Pourquoi n'utilisez-vous simplement pas la liste et vous obtenez toutes les fonctions Where et Linq gratuitement ... – chugh97

Répondre

1

Cela fera ce que vous voulez. Remarque, j'ai extrait le IEnumerable pour le rendre réutilisable et réduit la complexité de toutes les autres 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(); 
    } 
} 
4

Vous pouvez appeler Cast<Customer>() sur votre IEnumerable qui vous donnera un IEnumerable<Customer>, ou tout simplement mettre en œuvre IEnumerable<Customer> pour commencer. LINQ est presque entièrement accroché dans IEnumerable<T>, pas IEnumerable. Une fois que vous avez fait cela, vous obtiendriez tout le LINQ à la bonté des objets gratuitement.

+1

Vous ne devriez probablement pas mettre votre énumérateur en cache, mais en renvoyer un nouveau à chaque appel de 'GetEnumerator', chaque appel à' GetEnumerator devrait renvoyer un objet capable d'énumérer la collection sans avoir à ajouter quoi que ce soit d'autre. Avoir deux énumérations partagent le même énumérateur est problématique. –

2

Je recommande d'utiliser OfType<T>() au lieu de Cast<T>() parce que si votre collection contient T1 et T2, collection.Cast<T1>() jetteront une erreur alors que collection.OfType<T1>() retournera IEnumerable<T1> ne contient que des cas de T1 ne T2

+0

Ah, mais est-ce nécessairement une mauvaise chose de lancer une exception quand il y a un élément inattendu? –

+0

@Kirk: Selon un cas, bien sûr. 99.99% du temps où j'utilise 'OfType' convertit toutes ces collections non génériques intégrées .NET 2.0 comme ControlCollection, ElementCollection, etc., sur IEnumerable, donc je ne suis pas sûr de ce qu'elles contiennent exactement. une vérification additionnelle est ok – abatishchev

+2

bien, le nom de sa classe s'appelle "CustomerCollection" donc il semblerait surprenant (et digne d'une exception) s'il devait contenir autre chose. :) –

1
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(); 
    }  

} 
1
new List<Customer>(myCustomerEnumerator); 
1

La classe de base recommandée à utiliser pour créer vos propres implémentations de collection est System.Collections.ObjectModel.Collection<T>

(MSDN)
Cette classe de base est fourni pour le rendre plus facile pour créer une implémenteurs de collection personnalisée. Les implémenteurs sont encouragés à étendre cette classe de base au lieu de créer la leur.

public class CustomerCollection : Collection<Customer> 
{ 
}