Casablanca: Typumwandlung

Hallo Fortum,

ich habe in einer generischen Methode diese Programmzeile:

  
  var myArray = dateList.ToList().ConvertAll(d => Convert.ToDateTime(d));  

Nun muss eine Fallunterscheidung gemacht werden:

  
   if(bedingung = 1)  
      myArray = dateList.ToList().ConvertAll(d => Convert.ToString(d));  
   if(bedingung = 2)  
      myArray = dateList.ToList().ConvertAll(d => Convert.ToDateTime(d));  

Dies bedutet, dass die Variable "myArray" außerhalb der if-Abrage deklariert werden muss. Es könnte so sein:

  
   IEnumerable<DateTime> myArray = null;  

Da aber die dataList in verschiedenen Typen convertiert werden kann (hier z.B. DateTime oder String) sollte eingentlich sowas hin:

  
   IEnumerable<typeOf<T>> myArray = ...  

Das kann aber so nicht klappen. Hat jemand eine Idee, wie soetwas gehandhabt wird?

Gruß

  1. Tach!

    ich habe in einer generischen Methode diese Programmzeile:
    var myArray = dateList.ToList().ConvertAll(d => Convert.ToDateTime(d));

    Das "var" kann man aus Faulheitsgründen hinschreiben, dann sollte man aber den Resharper beauftragen, den eigentlichen Typ hinzuschreiben. Der Compiler kann den erkennen, der Mensch - besonders wenn er nur einen Codeausschnitt zu sehen bekommt - tut sich etwas schwer damit. Zumal hier auch noch fehlt, dass man mit der Maus draufzeigen kann, um den eigentlichen Typ angezeigt zu bekommen.

    Dies bedutet, dass die Variable "myArray" außerhalb der if-Abrage deklariert werden muss. Es könnte so sein:
    IEnumerable<DateTime> myArray = null;
    Da aber die dataList in verschiedenen Typen convertiert werden kann (hier z.B. DateTime oder String) sollte eingentlich sowas hin:
    IEnumerable<typeOf<T>> myArray = ...
    Das kann aber so nicht klappen. Hat jemand eine Idee, wie soetwas gehandhabt wird?

    Nur IEnumerable<T>, denn T ist bereits ein Typ, in dem Fall ein Stellvertreter für den später verwendeten.

    dedlfix.

    1. Hi,

      dnake. Leider habe ich nichts verstanden. Ein Stellvertreter für T in IEnumerable<T>? Das ist ja an dieser Stelle mein Problem. Wie geht das? Man kann nicht einfach IEnumerable<T> als Datentyp hinschreiben. Ich habe auch versucht, die ganze Liste samt Datentyp (typof(T)) zur Laufzeit zu generieren, hat aber nicht geklappt.

        
         Type myType = typeOf(T);  
         IEnumerable<myType > myArray = null;  
         if(bedingung = 1)  
            myArray = dateList.ToList().ConvertAll(d => Convert.ToString(d));  
         if(bedingung = 2)  
            myArray = dateList.ToList().ConvertAll(d => Convert.ToDateTime(d));  
      
      

      Das "var" wird nicht aus Faulheit hingeschrieben, sondern wird dies auch von Resharper empfohlen. An dieser Stelle geht es auch nicht darum. Vielleicht bin tatsächlich etwas faul. Das wusste ich auch nicht, dass man soviel mit der Maus machen kann????!!!!! Staunlich!

      Gruß

      1. Tach!

        Leider habe ich nichts verstanden. Ein Stellvertreter für T in IEnumerable<T>?

        Das T ist der Stellvertreter, der in der generischen Klasse für den Typ steht, der am Ende verwendet wird.

        Das ist ja an dieser Stelle mein Problem. Wie geht das? Man kann nicht einfach IEnumerable<T> als Datentyp hinschreiben.

        Doch, das kannst du. Das T muss aber in der Klasse oder zumindest in der Methode nochmal auftauchen.

        public class Foo<T> {
          public void Func() {
            IEnumerable<T> bar;
          }
        }

        public class Foo {
          public void Func<T>() {
            IEnumerable<T> bar;
          }
        }

        Im ersten Beispiel weiß die Klasse, dass sie generisch ist, im zweiten ist es nur die Methode.

        Bei der Verwendung gibst du dann an, was T konkret sein soll, also

        Foo foo = new Foo<DateTime>(); // erstes Beispiel

        oder

        Foo foo = new Foo(); // zweites Beispiel
        foo.Func<DateTime>();

        Manchmal kann man das <DateTime> bei Methodenaufrufen weglassen, wenn der Compiler aus dem übergebenen Argumenten den Typ entnehmen kann.

        Foo foo = new Foo(); // zweites Beispiel
        DateTime date;
        foo.Func(date);

        Wenn allerdings weder die Klasse noch die Methode ein <T> haben, kannst du kein T verwenden, sondern musst einen konkreten Typ angeben. Zur Not object und dann casten.

        Das "var" wird nicht aus Faulheit hingeschrieben, sondern wird dies auch von Resharper empfohlen. An dieser Stelle geht es auch nicht darum. Vielleicht bin tatsächlich etwas faul. Das wusste ich auch nicht, dass man soviel mit der Maus machen kann????!!!!! Staunlich!

        Der Resharper kann das var in beide Richtungen umwandeln. Ich finde, es macht den Code schwerer lesbar. Deswegen geh ich immer die Richtung zum Expliziten. Aber jetzt wo du es sagst, erinnere ich mich, dass er das am Anfang auch so empfahl, und ich ihn alsbald umkonfigurierte.

        dedlfix.

        1. Hallo,

          danke für deine klare Erklärung. Meine Methode nimmt ein "IEnumerable<T>" entgegen.

            
            
          GetList<DateTime>(myDatTimeListAsToList);   //Aufruf  
            
          private void GetList<T>(IEnumerable<T> myDate) {  
            
          }  
          
          

          Das Ganze wandle ich in dieser Funktion, wie vorhin erwähnt, in einem DateTime-Typ um:

            
          private void GetList<T>(IEnumerable<T> myDateList) {  
              IEnumerable<DateTime> myArray = myDateList.ToList().ConvertAll(d => Convert.ToDateTime(d));  
          }  
          
          

          Das funktioniert so auch gut. Ich wollte nun diese Funktion insoweit erweitern, dass ich unterschiedliche Listen mit unterschiedlichen DatenTypen in dieser Funktion behandeln kann. Also musste ich erst mal die Datentypen ermitteln und anhand deren Typen eine Convertierung durchführen. Und da komme ich nicht weiter, weil ich nicht genau weiß, wodurch ich den "IEnumerable<DateTime>"-Datentyp im oberen Beispiel ersetzen soll:

            
          private void GetList<T>(IEnumerable<T> myDateList) {  
            
              IEnumerable<T> myArray;  //Mein Problem ist hier. Was muss hier stehen? IEnumerable<T> in der Form funktionirt hier nicht.  
            
              if(typeof(myDateList) == typeof(string))  
                  myArray = myDateList.ToList().ConvertAll(d => Convert.ToString(d));  
              if(typeof(myDateList) == typeof(DateTime))  
                  myArray = myDateList.ToList().ConvertAll(d => Convert.ToDateTime(d));  
            
          }  
          
          

          Wie erwähnt, ich habe versuch eine List<DateTime> zur laufzeit zu generieren. Obwohl ich hinterher eine DateTime-Liste erhalte, sieht es so aus, dass die Daten trotzdem keine richtige DateTime-Typen sind, weil ich daruaf z.B. keine Linq-Anweisung wie diese:

            
          private void GetList<T>(IEnumerable<T> myDateList) {  
            
              IEnumerable<T> myArray;  
            
              if(typeof(myDateList) == typeof(string))  
                  myArray = myDateList.ToList().ConvertAll(d => Convert.ToString(d));  
              if(typeof(myDateList) == typeof(DateTime))  
                  myArray = myDateList.ToList().ConvertAll(d => Convert.ToDateTime(d));  
            
              List<SelectListItem> item = new List<SelectListItem>();  
              items.AddRange(myDateList.Select(date => new SelectListItem  
                      {  
                          Text = date.ToString("dd.MM.yyyy"),  
                          Value = date.ToString("dd.MM.yyyy"),  
                      }));  
            
          }  
          
          

          Hier wird z.B. nach der Typumwandlung zur Laufzeit die ToString("dd.MM.yyyy") mit einem Parameter nicht mehr erkannt. Mit dem expliziten Datentyp "IEnumerable<DateTime> myArray" ist aber alles in Ordnung.

          Gruß

          1. Tach!

            Das Ganze wandle ich in dieser Funktion, wie vorhin erwähnt, in einem DateTime-Typ um:

            private void GetList<T>(IEnumerable<T> myDateList) {
                IEnumerable<DateTime> myArray = myDateList.ToList().ConvertAll(d => Convert.ToDateTime(d));
            }

              
            Ein  
              
            IEnumerable<DateTime> myArray = myDateList.Cast<DateTime>();  
              
            sollte es auch tun.  
              
            
            > private void GetList<T>(IEnumerable<T> myDateList) {  
            >   
            >     IEnumerable<T> myArray;  //Mein Problem ist hier. Was muss hier stehen? IEnumerable<T> in der Form funktionirt hier nicht.  
              
            myDateList ist ja bereits IEnumerable<T>, das wäre ja schon da. Ansonsten versuchst du hier an der starken Typisierung C#s vorbeizuarbeiten. Du willst etwas haben, das mal den einen und mal den anderen Typ annehmen kann. Das gibts nur in der Form dynamic:  
              
            dynamic myArray;  
              
            Damit ist dann keinerlei Typ zur Compile-Zeit mehr verfügbar und auch Dinge wie Codevervollständigung sind dafür nicht verfügbar.  
              
            
            >     if(typeof(myDateList) == typeof(string))  
              
            myDateList ist die gesamte Liste. Nur deren Elemente sind vom Typ string (oder was anderes), nicht die Liste selbst. Du musst da schon das T vergleichen:  
            typeof(T) == typeof(string)  
              
            
            > Wie erwähnt, ich habe versuch eine List<DateTime> zur laufzeit zu generieren. Obwohl ich hinterher eine DateTime-Liste erhalte, sieht es so aus, dass die Daten trotzdem keine richtige DateTime-Typen sind, weil ich daruaf z.B. keine Linq-Anweisung wie diese:  
              
            Erst nach einem Typecast geht das. (Oder wenn du T auf DateTime einschränkst, was du ja nicht willst.) Auch mit dem dynamic brauchst du einen Typecast zum konkreten Typ, wenn du die Liste weiterverarbeiten möchtest. Zum Beispiel so:  
              
            IEnumerable<string> result = ((IEnumerable<DateTime>)myArray).Select(item => item.ToShortDateString());  
              
            Ich kenne die Hintergründe deines Vorhabens nicht, aber mir scheint das - obwohl man das irgendwie hinbekommt - nicht die Lösung für das eigentliche Problem zu sein. Warum kommen in der Liste unterschiedliche Typen an? Warum muss man die gemeinsam bearbeiten, dann aber doch unterschiedlich? Warum können es keine spezialisierten Verarbeiter für die jeweiligen Typen von Daten sein?  
              
              
            dedlfix.
            
            1. Hi,

              vielen Dank.
              In der Liste komme keine unterschiedlichen Typen vor. Es gibt, einfach gesagt, z.B. zwei ComboBoxen(Listviews). Eine beinhaltet Daten (Tage) vom Typ DateTime und die andere z.B. Einkäufe vom Typ String. Diese werden von d Datenbank als List zurückgegeben, die dan, wie angegeben, in eine Auswahlliste reingepackt- Im Grunde genommen, ist der Vorgang derselbe. Also liegt es nahe, diese über eine Methode zu bearbeiten. Daher versuche ich die eine Methode füe beide Vorgänge zu relisieren.

              An dieser Stelle gibt es auch eine Konvertierungsproblem mit dynamic.

              Gruß