Member einer Klasse soll von außerhalb der Klasse nur gelesen werden können
-
Ich hab da ein kleines Konzeptionsproblem. Und zwar habe ich folgende Klassen:
class InneresObjekt { public int Zahl { get; private set; } public void VerändereZahl() { ... } } class ÄußeresObjekt { private InneresObjekt inner; public void MachWas() { if (...) inner.VerändereZahl(); } }
Die Main-Funktion hat jetzt ein Objekt von Typ
ÄußeresObjekt
. Wann immer sie die FunktionMachWas
aufruft (oder in anderen Situationen), soll sie den aktuellen Status voninner
checken. Für diesen Fall braucht die Main ja nur den Wert vonZahl
. Aber wie mach ich den am besten bekannt? Wenn ichinner
public machen würde, könnte die Main auch dieVerändereZahl
-Funktion aufrufen, was ja nicht sein soll. Allerdings find ich es auch redundant, in dieÄußeresObjekt
-Klasse jetzt folgendes einzubauen:public int InnerZahl { get { return inner.Zahl; } }
Immerhin kann es passieren, dass
ÄußeresObjekt
noch mehr Member bekommt, auch von anderen Typen, oder dass inInneresObjekt
noch sonstwas hinzu kommt. Und die Main soll dann von jedem der Member den Status checken können. Das wären eine ganze Menge zusätzlicher Properties.
Ich hab mir auch überlegt, die beiden Klassen in eine extra Assembly zu packen und dann dieVerändereZahl
-Funktion internal zu machen, so dassÄußeresObjekt
auf sie zugreifen kann, die Main aber nur auf den Getter vonZahl
. Aber das ist auch wieder nicht so optimal. Immerhin soll die Lösung ja auch möglichst allgemeingültig sein. Und man kann sich nicht drauf verlassen, dass man in solcherlei Konstrukten immer eine separate Assembly hat.
Was kann ich also tun, damit die Main zwar alle nötigen Informationen bekommt, das innere Objekt aber nicht verändern kann?
-
Hab ich das richtig Verstanden du willst den Zugriff auf InnereKlasse von außen verbieten aber der ÄußeresObjekt Klasse den zugriff erlauben?
Dann mach doch einfach eine Nested Class, die auf private und gut ist.
-
Firefighter, er will ja auf 'Zahl' von außen zugreifen können.
Du könntest einfach die Methode 'VerändereZahl' als internal deklarieren:
internal void VerändereZahl();
Dann können nur Klassen der eigenen Assembly darauf zugreifen (evtl. also einfach deine Klassen in eine eigene Klassenbibliothek auslagern).
Ansonsten ginge auch noch ein anderer Weg mittels Vererbung:
class InneresObjekt { public int Zahl { get; protected set; } } class InneresObjekt2 : InneresObjekt { public void VerändereZahl() { ... } } class ÄußeresObjekt { private InneresObjekt2 inner; public InneresObjekt InnerObjekt { get { return inner; } } }
Nach außen ist also nur 'InneresObjekt' bekannt und intern wird aber 'InneresObjekt2' verwendet...
-
Achso auf Zahl, gut das hab ich missverstanden.
-
Das mit dem internal hab ich mir auch schon überlegt, aber das würde bedeuten, dass, wann immer man auf so ein Problem stößt, man eine eigene Assembly erstellen muss.
Das mit der Vererbung funktioniert, soweit ich sehe, nicht, weil man hier ganz leicht eine explizite Typumwandlung vornehmen könnte.
Es ist Mist, dass es in C# nicht sowas wie konstante Methoden (so wie in C++) und konstante Referenzen gibt. Dann könnte man einfach folgendes machen:
class InneresObjekt { public int Zahl { get const; private set; } public void VerändereZahl() { ... } } class ÄußeresObjekt { private InneresObjekt inner; public const InneresObjekt Inner { get { return inner; } } public void MachWas() { if (...) inner.VerändereZahl(); } }
Das Property in Zeile 12 wäre dann eine const reference und dürfte nur von eben so einer Variable übernommen werden:
ÄußeresObjekt x = new ÄußeresObjekt(); InneresObjekt y = x.Inner; // Fehler: Konstanter Referenztyp kann nicht auf Variable belegt werden. const InneresObjekt x = x.Inner; // Alles OK.
Aber sowas gibts ja leider nicht.
-
EDIT (letzte Variable von x in z umbenannt):
ÄußeresObjekt x = new ÄußeresObjekt(); InneresObjekt y = x.Inner; // Fehler: Konstanter Referenztyp kann nicht auf Variable belegt werden. const InneresObjekt z = x.Inner; // Alles OK.
-
Die einfachste Möglichkeit ist hier IMO nicht die schlechteste:
Cäpt'n Balu schrieb:
class InneresObjekt { public int Zahl { get; private set; } public void VerändereZahl() { ... } } class ÄußeresObjekt { private InneresObjekt inner; public void MachWas() { if (...) inner.VerändereZahl(); } // kannst den Namen hier auch gern ändern - "InnerZahl" oder was auch immer public int Zahl { get { return inner.Zahl; } } }
Sonst würde ich hier statt Vererbung grundsätzlich eher ein Interface verwenden. Grundsätzlich soll heissen: wenn sonst kein guter Grund für Vererbung oder gegen ein Interface spricht.
-
hustbaer schrieb:
Die einfachste Möglichkeit ist hier IMO nicht die schlechteste
Der Quellcode ist ja nur ein vereinfachtes Beispiel. Stell dir aber mal vor, ich hab in der äußeren Klasse mehrere Member, auch von verschiedenen Typen, und die mehreren Member haben ihrerseits jeweils mehrere Member. Und all das würde den Status ausmachen, der von außen zu lesen sein muss. Dann wäre es ziemlich aufwändig und dazu redundant, wenn ich für jedes Property der inneren Klassen noch ein Property in der äußeren Klasse stehen hätte.
hustbaer schrieb:
Sonst würde ich hier statt Vererbung grundsätzlich eher ein Interface verwenden. Grundsätzlich soll heissen: wenn sonst kein guter Grund für Vererbung oder gegen ein Interface spricht.
Also, mit Vererbung und Interfaces etc. hat mein Problem ja sowieso generell gar nichts zu tun.
-
dann bring ein realistisches beispiel
-
Cäpt'n Balu schrieb:
Also, mit Vererbung und Interfaces etc. hat mein Problem ja sowieso generell gar nichts zu tun.
Und was wäre am INterface-Ansatz denn falsch? Folgendes Beispiel erfüllt doch Deine Anforderungen:
interface IInnerObject { int Zahl { get; } } class ÄußeresObjekt { private class InneresObjekt : IInnerObject { public int Zahl { get; private set; } public void VerändereZahl() { } } private InneresObjekt inner = new InneresObjekt(); public IInnerObject Inner { get { return inner;} } }
Cäpt'n Balu schrieb:
Der Quellcode ist ja nur ein vereinfachtes Beispiel. Stell dir aber mal vor, ich hab in der äußeren Klasse mehrere Member, auch von verschiedenen Typen, und die mehreren Member haben ihrerseits jeweils mehrere Member. Und all das würde den Status ausmachen, der von außen zu lesen sein muss. Dann wäre es ziemlich aufwändig und dazu redundant, wenn ich für jedes Property der inneren Klassen noch ein Property in der äußeren Klasse stehen hätte.
Dann stellt sich die Frage ob das zu Grunde liegende Design nicht flawed ist. Warum eine private kllasse machen wenn man dann große Mengen davon doch public zur Verfügung stellt? Das widerspricht dem Konzept der Kapselung.
-
Ich kann den Grundgedanken schon verstehen, daß man nur lesend auf ein Objekt von außen zugreifen möchte, und der schreibende Zugriff nur von einer bestimmten Klasse aus erlaubt sein soll.
Deswegen wünsche ich mir für C# auch ein "const" für Methoden (bzw. automatisch für Getter-Properties).
Für Collections z.B. wurde dafür extra eine ReadOnlyCollection geschaffen.Ausweg bleibt daher wie beschrieben nur über Vererbung oder Interfaces (d.h. Mehraufwand beim Schreiben der Klassen).