Laden...

Auf Methoden von unbekannten Objekte durch Interface zugreifen

Erstellt von Garzec vor 6 Jahren Letzter Beitrag vor 6 Jahren 2.221 Views
G
Garzec Themenstarter:in
50 Beiträge seit 2016
vor 6 Jahren
Auf Methoden von unbekannten Objekte durch Interface zugreifen

Hallo,
ich habe mich mal ins Thema Interfaces eingelesen.

Nun übe ich anhand von einem wirklich sehr simplen Spiel, es gibt 4 verschiedene "Zellen". Diese Zellen erben von einer Zellbasis.

public abstract class CommonCell{}

Jede Zelle enthält Informationen und implementiert durch das Interface Methoden.

Alle erzeugten Zellen werden in einer Liste gespeichert. In der Klasse, wo sich auch die Liste mit den Zellen befindet, möchte ich jede einzelne Zelle ansprechen und eine Methode aufrufen.

An die Methode müsste ich doch gelangen, da durch das Interface sichergestellt ist, dass diese Methode vorhanden ist. Ich weiß aber nicht so recht, wie ich die foreach-Schleife aufzubauen habe.


// Cells ist die Zell-Liste
foreach(Cell c in Cells)
{
      c.Methode();
}

Wie muss ich "Cell c" schreiben, das gibt es nicht, ich habe nur die abstrakte Basis und die Kinder Zelle1, Zelle2, Zelle3, Zelle4.

Also quasi eine allgemeine Referenz zu allen Zellen und darüber der Methodenaufruf..

Ich stehe da grade ein wenig auf dem Schlauch.

P
64 Beiträge seit 2011
vor 6 Jahren

Guten Morgen,

Du erzeugtst eine Liste mit deinen Zellen.

also:


List<Cell> cellList = new List<CommonCell>();

und dann kannst du die Liste befüllen mit:


cellList.Add(new Zelle1); 
cellList.Add(new Zelle2); 
cellList.Add(new Zelle3);
cellList.Add(new Zelle4);  

Dann kannst du mit foreach durch die Liste iterieren.

3.003 Beiträge seit 2006
vor 6 Jahren

Zuerst einmal ist eine abstrakte Klasse kein Interface. Das mag wie Haarspalterei erscheinen, aber die Konzepte "abstrakte Superklasse" und "Interface" sollte man sauber auseinanderhalten. Schon allein, weil es da sprachlich ansonsten Missverständnisse gibt.

Zum zweiten: deine Zell-Liste ist vom Typ List<CommonCell>?

Dann:


foreach(CommonCell cell in Cells)
{
    cell.Methode(); //<- Wikipedia: Polymorphie lesen & verstehen.
}

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

G
Garzec Themenstarter:in
50 Beiträge seit 2016
vor 6 Jahren

Moment. Sorry. Ich kam vielleicht sehr unverständlich rüber.

Die Liste ist schon vorhanden, so wie du gesagt hast @panicJonny.

@LaTino das hatte ich falsch ausgedrückt. Ich habe ein Interface und diese abstrakte Klasse.

Dann versuche ich es nochmal zu beschreiben, ich habe die Basis

public abstract class CommonCell
{
// ist aktuell noch leer
}

dann habe ich noch das Interface

public Interface ICell
{
    void Methode1();
    void Methode2();
}

Und dann habe ich noch verschiedene Zellen.

public class Zelle1 : CommonCell, ICell
{
   public void Methode1()
{
// Tue dies
}

 public void Methode2()
{
// Tue jenes
}
}

public class Zelle2 : CommonCell, ICell
{
   public void Methode1()
{
// Tue dies
}

 public void Methode2()
{
// Tue jenes
}
}

Und diese Zellkinder liegen in einem Store. Dieser Store hält folgendes:


public class Store
{
    private List<Cell> cells = new List<Cell>(); // Wird gefüllt

    private void ActivateCells()
{
     foreach(Cell c in cells)
{
     c.Methode1();
     c.Methode2();
}
}
}

1.029 Beiträge seit 2010
vor 6 Jahren

Hi,

naja - wenn all deine Zellen von CommonCell erben und gleichzeitig auch das (mir unbekannte) Interface implementieren müssen, wäre es am einfachsten, wenn deine CommonCell auch das Interface "beerbt". (In einer abstrakten Klasse muss es ja nicht implementiert werden)

Dann könntest du die foreach-Schleife so lassen. Sofern das in deinem Aufbau so möglich ist, wäre das auch die beste Lösung.

So zum Beispiel:


public interface ICell
	{
		void Do();
	}

	public abstract class CommonCell : ICell
	{
		public abstract void Do();
	}

	public class MyCell1 : CommonCell {
		public override void Do()
		{
			throw new NotImplementedException();
		}
	}

	public class MyCell2 : CommonCell {
		public override void Do()
		{
			throw new NotImplementedException();
		}
	}

Wenn das nicht geht - dann wirst du die einzelnen Zellen "casten" müssen, dafür gibt es gleich mehrere Varianten:

Grundaufbau:


public interface ICell
	{
		void Do();
	}

	public abstract class CommonCell
	{
	}

	public class MyCell1 : CommonCell, ICell {
		public void Do()
		{
			// ignore
		}
	}

	public class MyCell2 : CommonCell, ICell {
		public void Do()
		{
			// ignore
		}
	}

Durchführung:


static void LoopWitCast()
		{
			// GetSampleData returns IEnumerable<CommonCell>
			// V1: Cast all of them
			foreach (var c in GetSampleData().Cast<ICell>())
			{
				c.Do();
			}

			// GetSampleData returns IEnumerable<CommonCell>
			// V2: Using as
			foreach (var c in GetSampleData())
			{
				var cell = c as ICell;
				cell?.Do();
			}

			// GetSampleData returns IEnumerable<CommonCell>
			// V3: Using direct cast
			foreach (var c in GetSampleData())
			{
				var cell = (ICell) c;
				cell.Do();
			}
		}

LG

G
Garzec Themenstarter:in
50 Beiträge seit 2016
vor 6 Jahren

oh cool, vielen Dank 😃

D
985 Beiträge seit 2014
vor 6 Jahren

Dabei sollte man noch explizit darauf hinweisen, dass eine Klasse nicht zwangsläufig alle Interface Methoden/Eigenschaften nach aussen posaunt, denn so ein Interface, bzw. die Methoden/Eigenschaften, kann/können an einer Klasse auch explizit implementiert sein.


interface IFoo 
{
    string GetName();
}

class Bar : IFoo
{
    public string GetName()
    { return "Bar"; }

    // explizite Implementierung von IFoo
    string IFoo.GetName()
    { return "IFoo"; }
}

void OutputBar( Bar barArg )
{ Console.WriteLine( barArg.GetName() ); }

void OutputFoo( IFoo fooArg )
{ Console.WriteLine( fooArg.GetName() ); }

void Output( Bar barArg )
{ Console.WriteLine( barArg.GetName() ); }

void Output( IFoo fooArg )
{ Console.WriteLine( fooArg.GetName() ); }

void Main()
{
    Bar bar = new Bar();
    OutputBar( bar ); // Bar
    // mit implizitem Cast nach IFoo
    OutputFoo( bar ); // IFoo

    Output( bar ); // Bar
    // mit explizitem Cast nach IFoo
    Output( bar as IFoo ); // IFoo
    Output( (IFoo)bar ); // IFoo
}