foreach - Eine Meinung

jccTeq

Erfahrenes Mitglied
Hallo Leute,

ich stolpere immer wieder darüber, daß man mit foreach keine selektive Auswahl in einer Collection treffen kann. Für mich ist foreach mangelhaft umgesetzt. Es wäre doch die einmalige Gelegenheit gewesen, den C# Entwicklern ein Konstrukt zu geben, welches über eine Collection eine Art SQL-, also Datenbank-Funktionalität abbildet. Worauf ich hinaus will, das ist folgendes:

ein normales foreach-Konsturkt sieht ja so aus:
Code:
foreach(Object bla in xxx)
{
...
}

in SQL sähe das ja so aus:
Code:
bla = sqlquery("select * from xxx");

jetzt wäre es schön gewesen, wenn man in foreach noch hätte selektieren können, welche Objekte aus xxx man benötigt, also wie in SQL:
Code:
select * from xxx WHERE blubb='bli';

was mit foreach so ähnlich hätte realisiert werden können:
Code:
foreach(bla in xxx where blubb=="bli")
... was eben in bla nur objekte geliefert hätte, deren Eigenschaft blubb den Wert "bli" enthält.

In der tatsächlichen Syntax der foreach muss man in jedem Schleifendurchlauf erstmal abfragen, ob blubb wirklich den Wert "bli" enthält:

Code:
foreach(bla in xxx)
{
  if(bla.blubb != "bli") continue;
}

Ich find's schade, daß es sowas nicht gibt... hätte mir schon 'ne Menge zusätzlicher Arbeit erspart.

Das ganze hätte man bestimmt auch noch weiter spinnen können, in Richtung SQL-Funktionalität. LIMITs und so... logische Verknüpfungen (WHERE blubb='bli' AND bloek='muh' oder so)...

Das ist meine Meinung! Was meint ihr dazu?
 

Alexander Schuc

crazy-weasel
Hi.

foreach mit einer Select-Anweisung aus SQL zu vergleichen passt, finde ich zumindest, nicht so ganz.
Mit dem SQL-Select holt man sich Datensätze gewisse Datensätze die gewisse Kriterien erfüllen.
Das foreach iteriert einfach durch eine Collection durch und du kannst dann mit jedem Objekt darin etwas machen. Eine Abfrage kannst dann im Anweisungsblock noch immer machen und ein
Code:
if (!bla.Blubb.Equals("blu"))
  continue;
ist ja nicht soviel Aufwand.

Machbar wäre aber ein von dir gewünschtes Konstrukt sicher. Wenn du es oft brauchst kannst es dir im Prinzip auch selbst schreiben. Nur schauts dann halt ein bisserl anders aus.
Es wird dann ein Funktionsaufruf sein dem du verschiedene Parameter übergibst, unter anderem auch einen Delegate zu einer Funktion die dann mit den gefundenen Objekten ausgeführt werden soll.

So könnte das aussehen:

Code:
/*
 *
 * A simple example how to extend the foreach-construct
 *
 * (c) 2004 Alexander Schuc
 * free for use and distribution
 *
 */

using System;
using System.Reflection;

namespace furred.Testing
{
  public class TestObject
  {
    public string Name;
    public int Number;
    
    public TestObject(string name, int number)
    {
      this.Name = name;
      this.Number = number;
    }
  }

  public delegate void mydelegate(TestObject obj);
  
  public class advancedForeachTesting
  {
    public static void Main(string[] args)
    {
      new  advancedForeachTesting();
    }

    private mydelegate executeStatement;
    
    public advancedForeachTesting()
    {
      TestObject[] to = new TestObject[20];
      for (int i = 0; i < 20; i++)
      {
        string name = i % 2 == 0 ? "Blaa" : "Blubb";
        to[i] = new TestObject(name, i);
      }

      object[] objs = new object[20];
      for (int i = 0; i < 20; i++)
      {
        int mod = i % 3;
        switch (mod)
        {
          case 0: objs[i] = (i+20); break;
          case 1: string name = i % 2 == 0 ? "Muh" : "Kuh";
                  objs[i] = new TestObject(name, i+20); break;
          case 2: objs[i] = "Blaa"; break;
        }
      }

      executeStatement  = new mydelegate(printInfos);
      Console.WriteLine("Testing with TestObject-Array:");
      aForEach("furred.Testing.TestObject", to, "Name", "Blaa", executeStatement);

      Console.WriteLine("Testing with object-Array:");
      aForEach("furred.Testing.TestObject", objs, "Name", "Kuh", executeStatement);
    }

    private void printInfos(TestObject obj)
    {
      Console.WriteLine("#{0:00} - {1}", obj.Number, obj.Name);
    }

    private void aForEach(string type_name, object[] collection, string prop, string equal, mydelegate fun)
    {     
      Type type = Type.GetType(type_name);
      
      foreach (object o in collection)
      {      
        if (o.GetType() == type)
        {
          string p = (string) type.InvokeMember(prop,BindingFlags.GetField, null, o, null);
          if (p == equal)
            fun((TestObject)o);
        }
      }
    }
  }
}

MfG,
Alex
 

Anhänge

  • advancedForeach.zip
    2,8 KB · Aufrufe: 22

Christian Fein

Erfahrenes Mitglied
foreach iteriert durch eine Collection nicht mehr und nicht weniger.

Was du haben willst ist demnach ein eigener Algorythmus Objecte anhand
eines Filters zu "finden".

Hier den Filter ein die Iteration einzubauen ist nicht wünscheswert. Denn
letztendlich müsste er in alle Klassen die eine Collection darstellen und
per foreach durchlaufen werden wollen unnötige Methoden bereitstellen.

Wenn du Collections haben willst die du aufgrund bestimmter Keys
bekommen willst dann ist es das richtige diese Collections in eine
Hashtable mit dem gewünschten Key zu packen.
 

XChris

Erfahrenes Mitglied
Meine Meinung:

Ne foreach ist zum DURCHLAUFEN von Container da. Den Selectiven Zugriff mit EINER Zugriffsmethode effizient erschlagen zu wollen ist unmöglich.

Du musst selbst entscheiden, was Du für einen Conatiner willst und brauchst. Das was Du Dir wünschst, nehmlich den Zugriff auf ein Element via Eigenschaft gibt es, Schau Dir mal - wie Christian Fein schon sagte, den Namespace Collection mal an. Wenn Du mal selbst eine verkettet Liste oder gewichteten Baum programmiert hast, weisst Du was ich meine.

Chris
 

Sunray

Erfahrenes Mitglied
Eine gute Idee wäre, selber eine Collection oder Dictionary (wegen den Primary Keys) Klasse zu schreiben, die über Reflection dann gewisse Ausdrücke auswerten kann.
VB.NET:
Code:
For Each resObj as Object in IntelligentCollection.Limit( _ 
   "param1 < 1900 and param2 = 'weihnachten' limit 3 sort by param1 asc")
	'//Code
Next

Im .NET Framework 2.0 könnte man das ganze sogar mit Generics machen...
Wirklich interessante Idee...
 

jccTeq

Erfahrenes Mitglied
@Schuc: Check deine Seite mal! Irgendwie scheint das ZIP-File defekt zu sein. Winzip sagt mir immer was von "Bad Offset". Und die Seite hinter [mehr] geht auch nicht.

Das mit der Collection, die eine Limit-Funktion liefert, welche SQL versteht, ist schonmal gar keine schlechte Idee. Trotzdem hätte ich es schön gefunden, wenn foreach das von Haus aus angeboten hätte.
 

Norbert Eder

Erfahrenes Mitglied
Es macht keinen Sinn das foreach für etwas zu missbrauchen, wofür es nicht gedacht war. Warum auch? Damit sollen Collections durchiteriert werden und sonst nichts. Überprüfungen können innerhalb durchgeführt werden.

Also warum hätte man foreach aufblasen sollen? Ich sehe hier wirklich keinen Grund dafür. Da macht es doch mehr Sinn, eine entsprechende Datenstruktur zu basteln oder was auch immer die das für mich übernimmt.
 

jccTeq

Erfahrenes Mitglied
Darum geht es mir ja. Um die Ursache dessen: darum, daß foreach für etwas anderes hätte vorgesehen werden können. Ums Prinzip. Man hätte ihm optional noch die Möglichkeit der Einschränkung geben können und so 'ne Menge Programmieraufwand einsparen können. Das ist es, was ich mit meiner Meinung aussagen wollte.
 

Neue Beiträge