Laden...

Indexer bei Array von Objekten verwenden

Erstellt von schock vor 19 Jahren Letzter Beitrag vor 19 Jahren 2.482 Views
S
schock Themenstarter:in
12 Beiträge seit 2005
vor 19 Jahren
Indexer bei Array von Objekten verwenden

Hallo,

ich lerne gerade C# und habe eine Frage:

Wie kann ich den Indexer bei einem Array von Objekten verwenden?

Beispiel:

 
class c
{
   private string[] s = new string[3];
   public string this[int i]
   {
      set
      {
          s[i] = value;
      }
    }
}

class o = new c();
o[1] = "Hallo Welt!"; // Wenn es nur ein Objekt gibt, geht es so.

class[] oo = new c[7];
oo**???** = "Hallo"; // Wie setze ich z.B. beim 5. Objekt des Arrays das 2. s auf "Hallo"?

Ich wuerde mich freuen, wenn mir jemand einen Tipp geben koennte.
Karl

49.485 Beiträge seit 2005
vor 19 Jahren

Hallo

mit


oo [4] [1] = "Hallo";

allerdings hast du mit


class[] oo = new c[7];

erst ein Arrray für sieben c-Objekte erzeugt. Es sind noch keine Objekte drin! Damit die Zuweisung oben auch funktioniert, braucht es mindestens noch:


oo [4] = new c ();

HTH

herbivore

S
schock Themenstarter:in
12 Beiträge seit 2005
vor 19 Jahren

Hallo,

erstmal muss ich sagen, dass mein Beispiel den Fehler enthaelt,
dass ich "class o = new c();" und "class[] oo = new c[7];" geschrieben
habe. Richtig muss es "c o = new c();" und "c[] oo = new c[7];" heissen.

Also so muss es heissen:


class c
{
  private string[] s = new string[3];
  public string this[int i]
 {
    set
    {
      s[i] = value;
    }
 }
}
...
c o = new c();
o[1] = "Hallo Welt!"; // Wenn es nur ein Objekt gibt, geht es so.

c[] oo = new c[7];
oo**???** = "Hallo"; // Wie setze ich z.B. beim 5. Objekt des Arrays das 2. s auf "Hallo"?

Der Vorschlag von herbivore: oo [4] [1] = "Hallo"; funktioniert nicht 😦

Es handelt sich ja auch nicht um ein zweidimensionales Array von Objekten
der Klasse c, sondern um ein eindimensionales Array von Objekten der Klasse
c, wobei die Klasse c als Member ein Array von strings hat.

Tschuess
Karl

49.485 Beiträge seit 2005
vor 19 Jahren

Hallo schock,

und wie das funktioniert, hier mal der Code als Ganzes:


using System;
using System.Collections;

class c
{
   private string[] s = new string[3];
   public string this [int i]
   {
      set
      {
         s[i] = value;
      }
   }
}

abstract class App
{
   public static int Main (string [] astrArg)
   {
      c o = new c ();

      o [1] = "Hallo Welt!";

      c [] oo = new c [7];

      oo [4] = new c ();

      oo [4] [1] = "Hallo";

      return 0;
   }
}

oo [4] liefert das fünfte Objekt in oo und das folgende [1] ist dann der Indexerzugriff auf ebendieses Objekt.

Ein Zugriff auf ein mehrdimensionales Array (von Strings) würde in C# sowieso anders aussehen, nämlich so:


oo [4,1] = "Hallo";

herbivore

4.506 Beiträge seit 2004
vor 19 Jahren

Hallo schock!

Ich bin etwas verwirrt, wegen 2 Dingen:

1.:
was willst Du mit der Zeile
c[] oo = new c[7];
erreichen? Ein Array von class c Objekten? Ich glaub das funktioniert so in dieser Art nicht.
Begründung:
eine Klasse muss mit einem Konstruktor instanziiert werden, hier ist c[] aber nie mit einem Konstruktor verbunden!

Ich würde es so schreiben:


Array myArray = new Array(4);
for(int i=0; i<4; i++)
   myArray[i] = new c();

  1. Deine Property Anweisung finde ich etwas befremdlich

  public string this[int i]
{
    set
    {
      s[i] = value;
    }
}

Begründung:
this ist ein Verweis auf die aktuell instanziierte Klasse, und wie funktioniert das mit der ArrayAnweisung direkt darauf folgend this[int i] ???

Ich würde in diesem Falle eine Methode schreiben, wenn dein string weiterhin 'private' bleiben soll:


public SetString(int indexPos, string val)
{
  s[i] = val;
}

Falls du deine strings s auch public setzen kannst/willst, dann geht es noch einfacher:


Array myArray = new Array(4);
for(int i=0; i<4; i++)
   myArray[i] = new c();

myArray[3].s[1] = "Hallo!";

Viel Spaß damit
Norman-Timo

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

49.485 Beiträge seit 2005
vor 19 Jahren

Hallol norman_timo,

nur verwirr den armen schock doch nicht:

  1. mit

Array oo = new Array (7);

erreicht man quasi das gleich wie mit:


c[] oo = new c[7];

nur das durch die - zweite in diesem Fall bessere - Variante klargestellt ist, dass die Array-Elemente vom Typ c sind. Die Anweisung von schock geht also voll in Ordnung.

Was aber in der Tat richtig ist, ist das in den erzeugten Feldern (Array bzw. c[]) noch keine Objekte enthalten sind. Will man diese erzeugen, kann man so eine Schleife verwenden, wie du das machst.

  1. Was schock verwendet, ist die Definition eines Indexers. Das this an dieser Stelle ist einfach Teil der Syntax und bedeutet nicht, was es an anderen Stellen bedeutet. Das geht also auch voll in Ordnung. Außerdem ist ja auch gerade der Titel der Frage "Indexer bei Array von Objekten verwenden".

  2. Instanzvariablen öffentlich zu machen ist (in der Regel) ein Verstoß gegen die Kapselung der Objeke; eine der grundlegenden Eigenschaften der Objektorientierung. Also bring schock hier nichts falsches bei. So wie er das gemacht hat, geht das voll in Ordnung.

herbivore

T
8 Beiträge seit 2005
vor 19 Jahren

hallo schock!
wieso ein array von objekten bauen, wenns die arraylist dafür gibt?
nur so zum beispiel der code angehängt! ist (imho) wesentlich besser zu bedienen.
gruß
tribal


using System;
using System.Collections;

namespace ConsoleApplication1
{

	class Class1
	{
		

		[STAThread]
		static void Main(string[] args)
		{	
			// ausgabevariable instanziieren
			string ausgabe;

			// wieso nen array von objekten machen, wenns dafür die arraylist gibt?
			ArrayList liste = new ArrayList();

			// arraylist mit 7 positionen füllen.
			for (int i=0; i<6; i++)
			{
				// an jede postion ein stringarray mit 8 positionen einfügen (oder irgendwas anderes...)
				liste.Add(new string[8]);
			}
			// stringarrays füllen (in welcher weise auch immer...)
			foreach (string[] sa in liste)
			{
				for (int i=0; i<7; i++)
				{
					sa[i] = "stelle " + i;
				}
			}
			
			//ausgabevariable mit dem zweiten string aus dem 5ten stringarray füllen...
			ausgabe = ((string[])liste[5])[2].ToString();

         // ausgeben
			Console.WriteLine(ausgabe);

		}
	}
}

// signaturplatz zu vermieten! 😉

4.506 Beiträge seit 2004
vor 19 Jahren

Hallo Herbivore!

  1. und 2.: Ja, gut zu wissen, so lernt man dazu!

  2. Für mich ist es nicht ersichtlich, ob das eine Instanzvariable ist. Ich persönlich verwende sehr wohl auch public Variablen in der Klassenebene, falls das absichtlich so gewünscht ist. (So würd ich sagen, dass trotzdem eine Kapselung möglich ist, aber eben nur wenn gewünscht!)

Trotzdem Danke, das mit dem this[index] muss ich mir mal anschauen, das hab ich bisher noch nicht gesehen.

Und dann, wenn das so ist, dass die Syntax korrekt ist, glaube ich nicht, dass ich schock damit dann verwirren könnte, weil das ja schon etwas komplizierter zu benutzen ist, und nur verwendbar, wenn man dementsprechend fest im C# Sattel sitzt 😉

Aber dass sind alles Vermutungen und weichen vom Thema ab...

Ciao
Norman-Timo

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

49.485 Beiträge seit 2005
vor 19 Jahren

Hallo norman_timo,

auch wenn das etwas Off-Topic ist:

Wenn du sowas willst wie öffentliche Instanzvariablen, dann solltest dafür Eigenschaften verwenden.

Also statt


public int iGewicht;

besser


private int iGewicht;

public int Gewicht {
   set { iGewicht = value; }
   get { return iGewicht; }
}

Damit werden u.a. spätere Änderungen erleichtert, weil man bei jedem Setzen und Abrufen der "Variablen" die Kontrolle bekommt und dort z.B. später zusätzlichen Code einfügen kann.

herbivore

S
schock Themenstarter:in
12 Beiträge seit 2005
vor 19 Jahren

Hallo,

> Der Vorschlag von herbivore: oo [4] [1] = "Hallo"; funktioniert nicht 😦

Asche auf mein Haupt.
Ich habe das nun ausprobiert. herbivore hat Recht, so geht es.

Was mich irritiert bzw. wo offensichtlich mein Denkfehler liegt:

1.: int[] ii = new int[7]; ii[4] = 5; // Geht.

2.: c[] oo = new c[7]; oo[4] [1] = "Hallo"; // Geht nicht.

3.: c[] oo = new c[7]; oo[4] = new c(); oo[4] [1] = "Hallo"; // Geht.

4.: int[] ii = new int[7]; ii[4] = new int(); ii[4] = 5; // Geht auch.

Weil 1. funktioniert, bin ich davon ausgegangen, dass 2. ebenso
funktioniert.

Irritierend finde ich, dass 4. moeglich/erlaubt ist, aber nicht
notwendig zu sein scheint, da es ja auch wie bei 1. geht.

Auf jeden Fall weiss ich jetzt, dass ich bei einem Array von
Objekten meiner Klassen fuer jedes Element ein Objekt mit
new erstellen muss.

Danke fuer die Hilfe.

Tschuess
Karl

49.485 Beiträge seit 2005
vor 19 Jahren

Hallo schock,

deine Verwirrung sollte sich klären, wenn du weißt, dass es in C# Wert-Typen (z.B. int, double, u.ä.) und Verweis-Typen (Object, FileStream und auch die meisten benutzerdefinierten Klassen) gibt.

Erzeugt man eine Variable eines Wert-Typs, ist darin Platz um den Wert aufzunehmen.

Erzeugt man eine Variable eines Verweis-Typs, ist darin Platz einen Verweis auf eine Objekt aufzunehmen. Dieser Verweis kann null sein, also die Variable enthält kein bzw. verweist auf kein Objekt.

Und ein Array ist ja einfach nur ein Feld von Variablen. Bei Wert-Typen hast du ein Feld von Werten und bei Verweis-Typen ein Feld von Verweisen (die eben zu Anfang alle null sind, also kein Objekt enthalten).

Weil int ein Wert-Typ ist und deine Klasse ein Verweis-Typ, erklärt sich der Unterschied.

herbivore