Announcement

Collapse
No announcement yet.

Übergabe von 'anonymous type' in Verbindung mit LINQ

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Übergabe von 'anonymous type' in Verbindung mit LINQ

    Hi,

    ich habe eine Klasse wie folge, in der ich eine LINQ-Anweisung bearbeite:

    Code:
        public static class GroupWords
        {
            public static IEnumerable<object> getGroupWords()
            {
                string[] words = { "hello", "wonderful", "linq", "beautiful", "world" };
    
                var groups = (from word in words
                                             orderby word ascending
                                             group word by word.Length into lenghGroups
                                             orderby lenghGroups.Key descending
                                             select new { Length=lenghGroups.Key, Words=lenghGroups});
    
    
                foreach (var group in groups)
                {
                    Console.WriteLine("Words of lenght " + group.Length);
                    foreach (var word in group.Words)
                    {
                        Console.WriteLine(" " + word);
                    }
                }
    
                return groups;
            }
        }
    Ich möchte nun die foreach-Schleife auslagern:

    Code:
       IEnumerable<object> groups = GroupWords.getGroupWords();
       foreach (var group in groups)
       {
            Console.WriteLine("Words of lenght " + group.Length);
            foreach (var word in group.Words)
            {
                 Console.WriteLine(" " + word);
             }
        }
    Das Problem ist, dass so die Eigenschaften "Length" und "Words" von group nicht mehr zur Verfügung stehen (Fehlermeldung). Ich habe bereits alle möglichen Konstlationen ausprobiert, habe ich aber keinen Erfolg gehabt. Weiß vielleicht jemand, wie das hier zu handhaben ist?

    Danke im Voraus.
    Zuletzt editiert von Smart; 27.11.2012, 19:09.

  • #2
    Hallo,

    anonyme Typen können nicht als Argumente od. Rückgabewerte von Methoden verwendet werden (steht auch so in der MSDN). Stattdessen kannst du einen bekannten Typ verwenden (eine Klasse od. eine Struktur) dafür verwenden. Ab .net 4.0 bzw. seit dem Einzug der DLR kannst du aber anonyme Typen als dynamic übergeben, obwohl ich bei einer Anforderung wie deiner klar zu einem bekannten Typ rate.

    mfG Gü
    "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

    Comment


    • #3
      Hi,

      danke für deine Antwort. Man setzt eigentlich LINQ ein, um solche bekannten Typen aus dem zu gehen. Ich wußte auch nicht wie ich das machen soll. Ich verstehe eigentlich auch nicht, warum die Eigenschften "Length" und "Words" zwar nach der Übergabe angezeigt aber nicht erkannt werden.

      Gruß

      Comment


      • #4
        Man setzt eigentlich LINQ ein, um solche bekannten Typen aus dem zu gehen
        Vielleicht aus Bequemlichkeit und weil es möglich ist aber sicherlich nicht weil es sinnvoll ist.

        der Übergabe angezeigt aber nicht erkannt werden.
        Falls du irgendein Control meinst dem du per Databinding die Klasse untergejubelt hast dann geht das weil die Klassenoberfläche per Reflection und nicht per statischer Typinformation abgefragt wird. Und bevor du fragst nur weil das System da Reflection benutzt solltest du es nicht auch tun. Reflection ist langsamer, weniger lesbar und potentiell fehleranfällig. Das sollte man nur dann benutzen wenn das notwenig ist und nicht weil man sich an anderer Stelle aus Bequemlichkeit erspart Klassen zu erstellen. (Und dann diese Bequemlichkeit damit bezahlt das man diesen anderen Stellen doppelt und dreifachen Aufwand hat).

        Das korrekte Vorgehen wäre hier eine Klasse zu Erzeugen die Length und Word darstellt und die zu verwenden. Die kannst du einfach im LINQ Ausdruck verwenden beim 'select new'. new ist ein ganz normaler Konstruktor Aufruf mit folgendem Typintialisierer. Bei dir kommt halt nur ein anonymer Typ raus weil du dir einfach sparst einen Typ anzugeben.

        Comment


        • #5
          Hallo Ralf,

          danke für deine Antwort.
          Ich bin nicht ganz sicher, ob ich dich richtig verstanden habe. Kannst du bitte diese Vorgehensweise mit einem Beispiel belegen.

          Danke im Voraus.

          Comment


          • #6
            Klasse schreiben

            [Highlight=C#]public class MeineLiebeKlasse
            {
            public int Length { get; set; }
            public IEnumerable<string> Words { get; set; }
            }[/Highlight]

            und dann einfach verwenden.

            [Highlight=C#]
            var groups = (from word in words
            orderby word ascending
            group word by word.Length into lenghGroups
            orderby lenghGroups.Key descending
            select new MeineLiebeKlasse { Length = lenghGroups.Key, Words = lenghGroups.ToArray() });
            [/Highlight]

            Comment


            • #7
              Hallo Ralf,

              vielen Dank. Das hatte ich auch in etwa verstanden und umgesetzt. Ich gebe "groups" dann als return-Wert zurück. Das Problem ist nun, wie ich in der Klasse mit der Schleife an die Properties komme, denn diese stehen immer noch nicht zur Verfügung:

              Code:
              	static void Main(string[] args)
              	{
              		IEnumerable<object> groups = GroupWords.getGroupWords();
              
              		foreach (object group in groups)
              		{
              			Console.WriteLine("Words of lenght " + group.Length);
              			foreach (var word in group.Words)
              			{
              				Console.WriteLine(" " + word);
              			}
              		}
              
              		Console.ReadLine();
              	}
              Gruß

              Comment


              • #8
                Weil du immer noch behauptest in der groups Aufzählung wärem nur object drin. du definierst die Rückgabe ja als IEnumerable<object>. Es stecken aber konkrete Klassen von einem konkreten Typ also zum Beispiel 'MeineLiebeKlasse' in der IEnumerable Aufzählung.

                Comment


                • #9
                  Schon verstanden. Die Zeile "foreach (object group in groups)" sollte so sussehen: "foreach (MeineLiebeKlasse group in groups)"

                  Vielen Dank nochmals.

                  Comment


                  • #10
                    Hallo,

                    geändert gehört "IEnumerable<object> groups". Dort statt object den tatsächlichen bekannten Typ verwenden.

                    mfG Gü
                    "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

                    Comment


                    • #11
                      Hi,

                      danke. OK, das ist richtig. Dafür muss die Methode getGroupWords() auch ein "IEnumerable<MeineLiebeKlasse>" zurückgeben. Ist das nicht besser, wenn man das Ganze allgemein (mit Object) hält? So braucht man bei einer eventuelen Änderung, nur an einer Stelle (select new MeineLiebeKlasse {...}) Änderungen vorzunehmen.

                      Gruß

                      Comment


                      • #12
                        Hallo,

                        nein das ist nicht besser, sondern sogar schlechter da auf die Typisierung bzw. deren Überprüfung durch den Compiler verzichtet wird. Auch entfällt so Boxing/Unboxing und Intellisense-Unterstützung vom VS bekommst so auch. Mit object hast du das alles nicht.

                        So braucht man bei einer eventuelen Änderung,
                        Probier das mal in einem richtigen Projekt, da dann nach einem Jahr nochmal geändert werden soll. Spätesten dann überdenkst du den "Vorteil" gewaltig.

                        mfG Gü
                        "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

                        Comment


                        • #13
                          Das läuft letztlich auf eine Diskussion über ~schwach typisiert~ oder ~stark typisiert~ hinaus. C# ist eine eher stark typisiert Sprache heißt Typen sollen möglichst zur Compilezeit feststehen. Das was du dir wünschst ist eine eher schwach typisierte Sprache wo erstmal jedes Ding angesprochen werden kann und erst zur Laufzeit festgestellt wird ob man das was man an diesem Ding aufruft auch wirklich existiert. (Aka Javascript und entsprechenden Dr**k)

                          So braucht man bei einer eventuelen Änderung, nur an einer Stelle (select new MeineLiebeKlasse {...}) Änderungen vorzunehmen.
                          Stell dir vor das was du dir wünscht ginge. Dann stell dir vor eine Änderung wäre die Umbenennung einer Property in der MeineLiebeKlasse Klasse (keine Zwischenrufe wegen Refactoring und so bitte). Zum Beispiel die Length Property soll in Zukunft Count heißen.
                          Da du dir wünscht das man das Ding einfach als Object rumreichen kann und trotzdem auf die Properties direkt per Bezeichner zugreifen kann (also Properties die Object nicht hat sondern nur MeineLiebeKlasse) bedeutet letztlich das zur Compilezeit nicht mehr geprüft werden soll ob das den ein gültiger Auruf ist. Heißt du könntest dann in MeineLiebeKlasse den Propertynamen ändern und es kompiliert und du kannst starten. Du hast aber vermutlich gar nicht den Code geändert der den Typ verwendet und immer noch Length abfragt (anstatt Count wie es nun heißt). Es würde also erst zur Laufzeit knallen da die aufgerufenen Length Property an diesem Object gar nicht existiert.

                          Wenn dir Bequemlichkeit wichtig ist aber Fehlerfreiheit eigentlich eher egal dann wähle eine schwach typisierte Sprache wenn dir aber Fehlerfreiheit wichtig ist dann wähle lieber eine Sprache die solche Dinge zur Compilezeit prüfen kann. Bisher gibt es keine (mir bekannte) Sprache die laxe Typisierung und strikte Prüfbarkeit zur Compilezeit verbindet. Ich habe da auch Vorstellungsprobleme das die Kombination möglich ist da die beiden Anforderung eigentlich wiedersprüchlich sind.


                          PS. ~stark typisiert~ bzw. ~schwach typisiert~ ist natürlich nur Umgangssprache. C# könnte man als 'statisch typisierte, typsichere Sprache mit Ausnahmen zur Umgehung der Typisierung' bezeichnen.

                          Comment

                          Working...
                          X