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
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
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
Hallo JuyJuka,
sicher? Ich würde denken, dass ConvertAll nicht auf IEnumerator, sondern nur auf IEnumerable funktioniert.
herbivore
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
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
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...
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();
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
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...
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
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.
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
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>();