Laden...

IEnumerator => IEnumerable<T> Ist das möglich?

Erstellt von dennisspohr vor 14 Jahren Letzter Beitrag vor 14 Jahren 1.555 Views
dennisspohr Themenstarter:in
420 Beiträge seit 2007
vor 14 Jahren
IEnumerator => IEnumerable<T> Ist das möglich?

Hallo zusammen,

in unserem Framework gibt es eine Collection namenes "Customers". Diese wird mit unseren Kunden gefüllt.
Nun würde ich alle Kunden gerne mittels einer einzigen Quellcodezeile in eine generische Liste kopieren.


Customers customers = session.CreateCustomers();
customers.FindAll();

List<Customer> customerList = new List<Customer>(customers.GetEnumerator());

Ist es möglich einen IEnumerator innerhalb einer Zeile in IEnumerable<T> "umzuwandeln"?

Danke für eure Hilfe!
Gruß Dennis

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo dennisspohr,

ja, das sollte sich machen klassen. Im Prinzip kannst du dafür einfach eine entsprechenden Cast-Operator schreiben. Da aber customers wohl die Methode GetEnumerator implementiert, würde ich darauf tippen, dass customer schon IEnumerable ist (oder sein sollte).

herbivore

2.187 Beiträge seit 2005
vor 14 Jahren

HI,

Ungetestet aber so sollte es gehen:

IEnumerable<Customer> re = new List<object>(customers.GetEnumerator()).ConvertAll<Customer>(delegate(object o){return o as Customer;})

Gruß
Juy Juka

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo JuyJuka,

sicher? Ich würde denken, dass ConvertAll nicht auf IEnumerator, sondern nur auf IEnumerable funktioniert.

herbivore

2.187 Beiträge seit 2005
vor 14 Jahren

Hallo herbivore,

ConvertAll ist von System.Collection.Generic.List, hab aber gerade festgestellt, dass der Konstruktor von List nur IEnumerable und nicht IEnumerator entgegen nehmen kann.

Gruß
Juy Juka

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo JuyJuka,

was ja genau der Grund ist, aus dem dennisspohr gefragt hat. 😃

Hallo dennisspohr,

was mich aber wieder zum eigentlichen Punkt zurückbringt, nämlich das Customers ein IEnumerable sein müsste oder zumindest sein sollte.

herbivore

3.971 Beiträge seit 2006
vor 14 Jahren

public class MyIEnummerableConverter<T> : IEnumerable<T> {
  private class MyIEnumeratorConverter<T> : IEnumerator<T> {
     private IEnumerator m_baseIEnum;
     public MyIEnumeratorConverter(IEnumerator baseIEnum) {
       m_baseIEnum = baseIEnum;
     }

     private T m_current;
     public T Current {
       get { return m_current; }
     }

     public bool MoveNext() {
       bool retval = m_baseIEnum.MoveNext();
       if (retval) {
         m_current = m_baseIEnum.Current as T;
       }
       else {
         m_current = default(T);
       }
       return retval;
     }
     
     public void Reset() {
       m_baseIEnum.Reset();
     }
  }

  private IEnumerable  m_baseIEnum;

  public MyIEnummerableConverter(IEnumerable baseIEnum) {
    m_baseIEnum = baseIEnum;
  }

  public IEnumerator<T> GetEnumerator() {
    return new MyIEnumeratorConverter<T>(m_baseIEnum.GetEnumerator());
  }

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

Einsatz:


new List<Customer>(new MyIEnummerableConverter<Customer>(customerlist))

Ist allerdings ungetestet. Fehler bitte melden

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

G
25 Beiträge seit 2009
vor 14 Jahren
Ja.

Also mit using System.Linq ist es einfach so:

IEnumerable<Customer> result = customers.Cast<Customer>();

Also wenn customers eine ICollection ist...

Wenn es nur ein IEnumerator ist?!

mmmm....
Hier nicht schön, aber eine Zeile 😃

IEnumerable<Customer> cust = new Func<IEnumerable<Customer>>(() => { var result = new List<Customer>(); IEnumerator en = customers.getEnumerator; while(en.MoveNext()) result.Add((Customer)en.Current); return result;} ).Invoke();

Christian Wirth

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo kleines_eichhoernchen,

Ist allerdings ungetestet. Fehler bitte melden

ein paar sind drin, z.B. dass das untypisierte GetEnumerator nicht implementiert ist, dass an einigen Stellen das <T> fehlt und dass teilweise IEnumerator und IEnumerable vertauscht sind. 😃

Aber warum so aufwändig? Es reicht doch:


using System;
using System.Collections.Generic;
using IUntypedEnumerator = System.Collections.IEnumerator;
using IUntypedEnumerable = System.Collections.IEnumerable;

public class IEnummerableConverter <T> : IEnumerable <T>
{
  private IEnumerator <T> _ienum;
  private bool            _fInUse = false;

  public IEnummerableConverter (IEnumerator <T> ienum)
  {
    _ienum = ienum;
  }

  public IEnumerator <T> GetEnumerator ()
  {
     if (_fInUse) {
        new Exception ("Bereits in Benutzung");
     }
     _fInUse = true;
     return _ienum;
  }

  IUntypedEnumerator IUntypedEnumerable.GetEnumerator ()
  {
     return GetEnumerator ();
  }
}

Man könnte überlegen, ob man das _fInUse weglässt und statt dessen vor dem Zurückgeben Reset () aufruft.

Hallo gourmelin,

Also wenn customers eine ICollection ist...

wenn customers eine ICollection wäre, gäbe es das Problem gar nicht. 😃

herbivore

3.971 Beiträge seit 2006
vor 14 Jahren

Hallo Herbivore,

Aber warum so aufwändig? Es reicht doch:

du musst doch aber auch den IEnumerator nach IEnumerator<T> umwandeln. Grund, IEnumerable.GetEnumerator() gibt einen IEnumerator zurück (und nicht wie gebraucht ein IEnumerator<T>)

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo kleines_eichhoernchen,

du musst doch aber auch den IEnumerator nach IEnumerator<T> umwandeln.

ok, da hast du recht. Das hatte ich übersehen. Dann fehlten in deinem Code die <T>s auch nicht, wie von mir behauptet, sondern es war Absicht, dass sie nicht angegeben waren. 😃

herbivore

G
25 Beiträge seit 2009
vor 14 Jahren

Also was ich nicht ganz verstehe hier:

wenn das hier möglich ist:

Customers customers = session.CreateCustomers();
customers.FindAll();

List<Customer> customerList = new List<Customer>(customers.GetEnumerator());

dann ist Customers ein IEnumarable, sonst könnte er nicht .GetEnumerator() aufrufen-

Die Linq Extension Cast<> gibt es für IEnumerable.

Also kann er einfach

customers.Cast<Customer>();

aufrufen.


Christian Wirth

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo gourmelin,

wenn customers eine ICollection wäre, gäbe es das Problem gar nicht. 😃

diesem meinem Einwand gegen deinen Vorschlag liegt der gleiche Fehler zugrunde, wie meinem Gegenvorschlag zu dem Code von kleines_eichhoernchen: Nämlich, dass ich nicht berücksichtigt habe, dass es hier darum geht von untypisierten Enummeratoren/Enummerationen zu typisierten kommen. Ich hatte mich nur auf die Umwandlung von Enummeratoren in Enummerationen fokussiert. Sorry!

herbivore

G
25 Beiträge seit 2009
vor 14 Jahren

Alles klar 😃 Seine Überschrift lautet ja auch:
IEnumerator => IEnumerable<T>

Also falls, aus was für Gründen auch immer, er wirklich nur einen IEnumerator in der Hand hat, würde ich eine Extension vorschlagen:

public static IEnumerable<T> ToGeneric<T>(this IEnumerator pEnum)
        {
            while (pEnum.MoveNext())
                yield return (T)pEnum.Current;
        }

Dann kann er einfach:

IEnumerator customers = //wo immer er die herbekommt;

IEnumerable<Customer> generic = customers.ToGeneric<Customer>();

Christian Wirth