Laden...

bei foreach auf referenz zugreifen

Erstellt von Darrn vor 17 Jahren Letzter Beitrag vor 17 Jahren 5.090 Views
D
Darrn Themenstarter:in
28 Beiträge seit 2006
vor 17 Jahren
bei foreach auf referenz zugreifen

hi!

ich habe ein array von referenzen auf die klasse Objekt und möchte diese gerne mit einer foreach schleife auf andere referenzen umändern.


Objekt[] nodes;

...Array füllen...

foreach ( Objekt node in nodes )
{
   node = new Objekt( this.getNext() );
}

der compiler sagt mir natürlich, dass ich auf eine foreach iteration variable nichts zuweisen darf. deshalb wollte ich fragen, wie man der foreach schleife angeben kann, dass sich die variable auf die referenz bezieht? in PHP geht das zB mit einem & vor dem variablennamen.

[php]
foreach ( $array as &$value )
{
...
}
[/php]

4.506 Beiträge seit 2004
vor 17 Jahren

Hallo Darrn,

ich kann Dir nicht folgen. Was möchtest Du tun?

Wenn Du ein dynamisches Array möchtest (also erst zur Laufzeit festlegen, wie groß das Array werden soll), dann verwende statt Array eine ArrayList.

Wenn Du ein fixes Array haben möchtest, dann kannst Du es folgendermaßen anlegen:



Objekt[] nodes = new Objekt[Anzahl];


Dann kannst Du allerdings nur Objekte vom Typ Objekt in das Array stecken. Falls Du verschiedene Typen in das Array geben möchtest, dann verwende lieber object, wobei ich davon abraten würde.

Foreach ist nämlich dafür da, durch eine bereits gefüllte Liste zu gehen, und die vorhandenen Instanzen abzugreifen. Eine erstmalige Befüllung sollte über den Index des Arrays erfolgen, und damit dann auch mittels einer "normalen" For-Schleife.

Gruß
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

D
Darrn Themenstarter:in
28 Beiträge seit 2006
vor 17 Jahren

ich möchte folgenden code abschnitt im foreach stil schreiben:


for ( int a = 0; a < nodes.Length; a++ )
{
   nodes[a] = new Object( getNext());
}

564 Beiträge seit 2005
vor 17 Jahren

Warum?

181 Beiträge seit 2006
vor 17 Jahren

foreach ( object node in nodes) kann so schon funktionieren, poste mal etwas mehr Code und deinen Fehler!
Denn geht nicht ist immer eine schlechte Beschreibung!!

4.506 Beiträge seit 2004
vor 17 Jahren

Hallo zusammen,

man kann definitiv die Referenzen, die temporär mit foreach erzeugt werden nicht innerhalb der foreach schleife verändern. Damit würde man die Reihenfolge und das abgreifen der nächsten Elemente durcheinander bringen.

Also ein



foreach (Irgendwas tempInstanz in IrgendWasAnderes)
{
   tempInstanz = Neuer Wert;
}


Ist definitiv nicht möglich. Dazu muss man wissen, wie foreach implementiert ist. Das kann man z.B. dann nachvollziehen, wenn man für seine eigenen Klassen mal IEnumerator und IEnumerable implementiert hat.

Das foreach greift hier Element für Element mittels GetNext() (oder MoveNext?) ab. Dabei müssen die Elemente in einer festen Reihenfolge stehen. Sollte sich jetzt ein Wert eines Elementes ändern, so kann die Reihenfolge durcheinander geraten sein, und es ist nicht mehr sichergestellt, dass Foreach noch so funktioniert wie es sollte.

Bei einer For-Schleife wird immer über einen Index zugegriffen, und daher ist diese Problematik hier nicht gegeben. Man könnte hier innerhalb der For-Schleife auch zwei Reihenfolgen vertauschen, jedoch würde der Zugriff auf den Index immer noch funktionieren. Die For-Schleife ist auch nicht dafür vorgesehen ALLE Elemente nur EINMAL zu durchlaufen, sondern ist allgemeingültig. Eine Foreach-Schleife ist definitiv so gedacht ALLE Elemente nur EINMAL zu durchlaufen, und da müssen solche Restriktionen gegeben sein.

Sorry, dass ich Dir hier nix anderes sagen kann...

Gruß
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

D
Darrn Themenstarter:in
28 Beiträge seit 2006
vor 17 Jahren

das sehe ich nicht so. die native implementation von foreach für arrays wird den aktuellen index irgendwo speichern und pro durchlauf erhöhen, wie in einer normalen for-schleife. ob sich das verweisziel eines element im array ändert ist für die reihenfolge unerheblich. bei collection kann das natürlich anders sein, die sind aber auch nicht nativ implementiert. und in PHP gehts auch... 😉

B
1.529 Beiträge seit 2006
vor 17 Jahren

Das ist aber nicht PHP sondern C#.
Und norman_timo hat die Funktionsweise von foreach genau richtig beschrieben. Auch wenn es theoretisch möglich wäre, in einem nicht dynamischen Array die Elemente während der Iteration zu ändern, würde das die Allgemeingültigkeit von foreach für alle Collections (IEnumerator) einschränken.

Sicherlich hast du Recht, wenn du schreibst, dass foreach für ein Arry die Indize inkrementiert und durchläuft. Das ist jedoch eine spezifische Implementation der IEnumerator Schnittstelle für ein Array. Und diese nicht zu kennen (müssen), ist eine der Grundlagen der OOP (Kapselung).

Ausserdem kann man bei


node[] nodes = new node[ anzahl ];
for( int i=0; i < nodes.Length; i++ )
{  nodes[i] = getNext();  }

wohl wahrlich kaum von kompliziert sprechen.
Eher davon, dass dein Klassendesign wahrscheinlich der Verbesserung bedarf.

4.506 Beiträge seit 2004
vor 17 Jahren

Hallo Darrn,

für alle Standard-Collections kann das durchaus sein, dass es über Index läuft. Aber Du hast die Möglichkeit doch eine eigene Implementierung von "GetNext() (oder MoveNext?)" vorzunehmen, und Foreach funktioniert trotzdem.

Da das dann der Fall ist, kann Foreach vorher nicht wissen, wie auf die Elemente zugegriffen wird, und daher kann sich die Reihenfolge auch ändern.

Wie gesagt, implementiere mal Spaßeshalber selbst IEnumerator und IEnumerable in Deiner eigenen Klasse mit z.B. einem Dictionary<string, string> Objekt als Datenspeicher, über den iteriert werden soll.

Dann wirst Du genau sehen, was ich meine...

Gruß
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

6.862 Beiträge seit 2003
vor 17 Jahren

PHP ist ja auch wohl kaum so streng typisiert wie C# 🙂

Foreachs werden in der Tat meistens zu for Schleifen optimiert, aber halt nicht immer, und genau deshalb kann man das bei foreach net erlauben die Referenz generell ändern zu lassen. Wie willst du denn Arrays von Collections bzw. von anderen Datenstrukturen die IEnumerable implementieren unterscheiden?

Baka wa shinanakya naoranai.

Mein XING Profil.

B
1.529 Beiträge seit 2006
vor 17 Jahren

Als kleiner semantischer Zusatz noch folgendes:


typeX[] bla = ...;
foreach( typeX i in bla )
{
     DoSomethingUsefull( i );
}

Da in einer Collection beliebige Objekte gespeichert sein können, benötigt der Compiler Typinformationen. Daher muss man i innerhalb des foreach-Kopfes als typeX deklarieren.
Damit ist i aber eine lokale Variable innerhalb der foreach-Schleife.

Das Zuweisen von Werttypen (struct) an i würde also nur die lokale Variable für den aktuellen Schleifendurchlauf (beim nächsten erhält sie ja einen neuen Wert) verändern.

Das Zuweisen von Referenztypen (class) an i würde eine Referenz auf das eigentliche Objekt speichern. Wird dieses nicht anderweitig referenziert, wird es vom Garbage Collector am Ende des Gültigkeitsbereichs (scope) von i (also am Ende eines Schleifendurchlaufs) abgeräumt.

Daher KANN man gar nichts zuweisen, was über die Schleife hinaus Bestand haben soll.

S
8.746 Beiträge seit 2005
vor 17 Jahren

Letztlich gehts hier um Performance. Will man einen Iterator schreiben, der das Verändern der Collection beim Iterieren erlaubt, dann kostet das Performance und/oder Speicherplatz.