2009-09-12 5 views

Répondre

30

Les méthodes d'extension LINQ existants travaillent sur des objets mettre en œuvre IEnumerable<T>. Je suppose que votre objet implémente l'interface non générique IEnumerable. Dans ce cas, vous pouvez utiliser la méthode d'extension Cast<T> pour obtenir un wrapper générique IEnumerable<T>. Par exemple, si les éléments sont de type int:

var wrapper = myObject.Cast<int>(); 

Vous pouvez maintenant utiliser LINQ sur l'emballage

0

Non, vous ne pouvez pas. Toutes les méthodes LINQ sont des méthodes d'extensions pour l'interface IEnumerable<T>.

Vous devrez donc implémenter IEnumerable<T> pour utiliser LINQ avec vos propres collections.

6

Pas directement. Vous pouvez écrire assez facilement un SingleShotEnumerable<T> si:

public sealed class SingleShotEnumerable<T> : IEnumerable<T> 
{ 
    private IEnumerator<T> enumerator; 

    public SingleShotEnumerable(IEnumerator<T> enumerator) 
    { 
     if (enumerator == null) 
     { 
      throw new ArgumentNullException("enumerator"); 
     } 
     this.enumerator = enumerator; 
    } 

    public IEnumerator<T> GetEnumerator() 
    { 
     if (enumerator == null) 
     { 
      throw new InvalidOperationException 
       ("GetEnumerator can only be called once"); 
     } 
     var ret = enumerator; 
     enumerator = null; 
     return ret; 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

Ceci est en supposant que vous réellement ont un IEnumerator<T>. Si vous n'avez que IEnumerator, vous pouvez écrire quelque chose de similaire en implémentant seulement IEnumerable, puis utiliser Cast ou OfType pour obtenir un IEnumerable<T>.

(Note: ceci est thread-safe Vous pouvez faire en sorte avec des serrures si vous vouliez vraiment..)

Vous pouvez alors faire:

var filtered = from person in new SingleShotEnumerable<Person>(personEnumerator) 
       where person.Age > 18 
       select person.Name; 

... mais vous couldn n'utilisez pas la requête deux fois.

Comment avez-vous dans la situation étrange de n'avoir un IEnumerator<T> de toute façon? C'est plutôt rare. Voyez si vous pouvez concevoir votre chemin autour de cela pour éviter d'avoir à faire quelque chose comme ce qui précède, ce qui est assez fragile.

(Une alternative serait de « vider » le IEnumerator<T> à un List<T> ou quelque chose de similaire, mais qui a des problèmes traitant de grandes ou potentiellement infinies séquences.)

+0

Certains types 'System.Windows.Forms', comme' ListViewItemCollection', ne semblent pas implémente 'IEnumerable '. –

+0

@ChrisAkridge: En effet, ils n'implémentent que le non-générique 'IEnumerable'. Mais vous pouvez toujours appeler 'Cast <>' pour créer un 'IEnumerable '. –

Questions connexes