Laden...

class ist referenz, wie leitet man ab ?

Erstellt von Ingo Boller vor 19 Jahren Letzter Beitrag vor 19 Jahren 5.424 Views
Ingo Boller Themenstarter:in
14 Beiträge seit 2005
vor 19 Jahren
class ist referenz, wie leitet man ab ?

Ich habe schwierigkeiten mit dem c#-Konzept der Refrenz bei class bzw. value bei struct.
Bespiel:
class myclass
{
public myclass(int _a){set(_a);}
public set(int seta){a=seta)

public int a;
};

Programm dazu:

myclass B(1);
myclass C(2);
B = C; // B zeigt auf C
C.set(5); // B und C enthalten 5
B.set(4); // B und C enthalten 4

Wenn ich oben nicht class myclass sondern struct myclass verwende, dann wäre am Ende des Programms C mit 5 belegt und B mit 4. So hatte ich das auch gewollt. Bei class myclass ist aber B und C mit 4 belegt.

  • class brauche ich zum ableiten, struct geht bekanntlich nicht dafür.
  • die class string erzeugt komischerweise keine Referenz
    string a = "HALLO";
    string b = "HUHU";
    a=b; // wert wird kopiert ?
    b="NEU"; // a bleibt auf HUHU;

kurzum: Wie kann man den gleichoperator so einsetzen, das das object nicht refrenziert, sondern kopiert wird. Das Ganze aber als
a=b;
und nicht
a=new myclass(b.a);
?

49.485 Beiträge seit 2005
vor 19 Jahren

Hallo Ingo,

vielleicht hilft dir schon mal etwas, was ich gerade in Indexer bei Array von Objekten verwenden zu Wert- und Verweis-Typen geschrieben habe.

herbivore

Ingo Boller Themenstarter:in
14 Beiträge seit 2005
vor 19 Jahren

Das hilft mir eigentlich leider nicht weiter. Mit Index, get/set und Arrays komme ich gut klar.

Ich suche eine Lösung für a=b einer Klasse. Es soll der inhalt kopiert werden und nicht der Pointer. Ich brauche quasi den operator =, den es aber nicht gibt.

Hast Du noch einen anderen Tip ?

49.485 Beiträge seit 2005
vor 19 Jahren

Hallo Ingo,

wohl ein Missverständnis. Ich meinte nicht die Info über den Indexer, sondern nur den einen offtopic darin enthaltenen Beitag über Wert- und Verweis-Typen.

herbivore

Ingo Boller Themenstarter:in
14 Beiträge seit 2005
vor 19 Jahren

Ja, habe ich gefunden, aber kannst Du das prezisieren ?

> 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)

Genau, es gibt Wert und Verweistypen (struct und class in meinem Beispiel)

Was heisst bei dir "die MEISTEN benutzerdefinierten Klassen ? So eine Klasse suche ich, die nicht Referenz ist. ODER: Die den Inhalt kopiert statt referenziert. So quasi ein Unique() aufruf oder eben einen =operator mit dem ich selbst entscheiben kann was bei
a=b
passiert.
Wie gesagt ist z.B. die class string nicht so, dass sie die Referenz kopiert. Meine selbsterstellten Klassen machen das aber leider so. Was muss ich tun ?

Die Doku bei Microsoft habe ich gelesen. C++ bin ich fit. Aber C# ist jetzt dran ...

49.485 Beiträge seit 2005
vor 19 Jahren

Hallo Ingo,

die Doku sagt:

Die Werttypen sind in zwei Hauptgruppen unterteilt:

  • Strukturtyp
  • Enumerationstyp

Strukturtypen umfassen benutzerdefinierte struct-Typen und folgende integrierte einfache Typen:

  • Numerische Typen
    • Ganzzahlige Typen
    • Gleitkommatypen
    • decimal
  • bool

und

In Variablen von Verweistypen, die auch als Objekte bezeichnet werden, werden Verweise auf die tatsächlichen Daten gespeichert. In diesem Abschnitt werden die folgenden Schlüsselwörter eingeführt, mit denen Verweistypen deklariert werden:

  • class
  • interface
  • delegate

Darüber [hinaus gibt es] [...] die folgenden integrierten Verweistypen [...]:

  • object
  • string

Sieht also schlecht aus. Ich würde momentan "die meisten benutzerdefinieren Klassen" in "alle benutzerdefinierten Klassen" ändern wollen. Vielleicht kann man aber auch über "integrierten Verweistypen" was machen.

herbivore

Ingo Boller Themenstarter:in
14 Beiträge seit 2005
vor 19 Jahren

Das wäre bitter. Ich war bisher vom c#-Konzept echt begeistert. Das ist der erste grobe Schnitzer in der Programmiersicherheit.
a=b kann schnell passieren und ist bei struct OK. Die Zeile danach sieht im Debugger immer richtig aus, doch das böse erwachen folgt später, wenn a oder b geändert werden, z.B. im Unterprogramm.

Ich kann das gar nicht glauben, aber so habe ich das auch gelesen, wenn auch auf englisch 😦

49.485 Beiträge seit 2005
vor 19 Jahren

Hallo Ingo,

Nachtrag:

  
string a = "HALLO";  
string b = "HUHU";  
a=b; // wert wird kopiert ?  
b="NEU"; // a bleibt auf HUHU;  

Der Test ist irreführen, weil er auch bei allen Verweistypen zum gleichen Ergebnis kommt:


MyObject b = new MyObject ();
a = b;  // "Wert" sprich Objekt wird nicht kopiert (nur der Verweis)
b = new myObjekt ();  // a verweist trotzdem immer noch auf das erste Objekt

HTH

herbivore

49.485 Beiträge seit 2005
vor 19 Jahren

Hallo Ingo,

Das wäre bitter. Ich war bisher vom c#-Konzept echt begeistert. Das ist der erste grobe Schnitzer in der Programmiersicherheit.

Das (Objekt-)Variablen nur Verweise auf Objekte enthalten ist kein Schnitzer, sondern dass es in C++ nicht so ist, ist ein Schitzer - nämlich ein Verstoß gegen das Konzept der Objektorientierung. Jede echte objektorientierte Programmiersprache (und da zähle ich C++ - auch wenn ich lange damit gearbeitet habe - mal nicht dazu) speichert in Variablen Verweise auf Objekte.

herbivore

1.373 Beiträge seit 2004
vor 19 Jahren

Vermutlich stiftet das Referenz vs. Wertetyp System bei C# mehr Verwirrung, weil Referenzen dort nicht explizit gekennzeichnet sind (anders als bei C++).

Wie auch immer. Was spricht dagegen, einfach ICloneable zu implementieren und statt

a = b

einfach

a = b.Clone() as MyClass

zu schreiben und damit auszudrücken, dass man sich bewusst ist, was man tut?

MfG VizOne

Ingo Boller Themenstarter:in
14 Beiträge seit 2005
vor 19 Jahren

Ich finde


a = b.Clone() as MyClass 

OK, aber nicht besonders schön. Man muß doch wieder C-typisch alles selbst kontrollieren und kann keinen High-Level-Code schreiben bzw. kann man keine Variablen im High-Level-Code kopieren.

Weiterhin geht doch auch


a = b+0;

wenn ich den operator + mit int verwende oder einen implizite umwandlung von int nach myclass zufuege
oder


a = b+0;

Neue Operatoren gehen ja scheinbar nicht, also


a ^= b;

wird nur durch ^ implementiert und faellt damit aus.
weiterhin ist a=b etwas völlig anderes als a=b+0;

Mal abgesehen von der etwas schlechteren Performance

@herbivore:
Ich fand es bisher gerade objectorientiert, das man a=b sagen kann und das object entscheiden lässt. Dies geht jetzt nicht (mehr) und ist in sofern nach meinem Empfinden eher Assembler orientiert mit Vorteilen bei Geschwindigkeit etc. als Highlevel gekapselte Funktionen, die durch die Implementierung des operator = entscheiden dürfen ob eine Referenz entsteht oder ein Clone.

struct macht das ja so. Nur kann man dann nicht ableiten. Mir fehlt insgesamt irgendwas bei struct oder class.

struct und class sind beide nicht objectorientiert, wenn man die Definitionen dazu mal durchgeht.

Was anderes: Gibt es zur class string einen Quellcode ?

Ingo Boller Themenstarter:in
14 Beiträge seit 2005
vor 19 Jahren

Ich noch einmal 🙂

Ich glaube ich habs jetzt gerafft:

  1. string ist auch nur eine Referenz
  2. Man darf Klassendaten nicht direkt manipulieren

Ich habe mir string mal genauer angesehen:
String hat keine Funktion die den String selbst verändert !
Meine Beispielklasse verwendet(e)


public void set(int _a)
{
   a = _a;         // interne Variable a setzen nach Vorgabe
}

Aufruf dann durch


a.set(5); 

Das darf man mit Klassen, die Referenzen sind, nicht machen !

Man muss darauf verzichten und


public myclass set(int a)
{
   return new myclass(a);
}

implementieren.
aufzurufen als


a = a.set(5);

Bei string geht das auch nur so


string s1 = "    HALLO     ";
string s2 = "   HUHU   ";
s1.Trim();    // Hier passiert nichts ! 
s1 = s1.Trim();   // jetzt wird s1 veraendert
s1 = s2.Trim();  // s1 bekommt neue Instanz aus Funktion Trim() und s2 bleibt unveraendert

in der letzten Zeile aendert sich s2 nicht

Also einfach keine (void) Funktionen mehr verwenden, die den inhalt einer Klasse selbst ändern.
Ist doch eigentlich ganz einfach 😁

333 Beiträge seit 2004
vor 19 Jahren

Original von Ingo Boller
struct und class sind beide nicht objectorientiert, wenn man die Definitionen dazu mal durchgeht.

Ne, du hast ein komplett falsches Verständniss von Objektorientierung. Java und C# stellen in der Hinsicht das Maß aller Dinge. Und es gibt zigtausende Programmierer die das so akzeptieren. Und jetzt kommst du und behauptest es sei nicht objektorientiert, nur weil du es einfach nicht erwartest oder einfach anders gewohnt bist? Wenn Referenzen nach deinem Verständnis nun die Objekte selbst repräsentieren, dann fängst du wieder mit Pointer-Wirtschaft an und das ist der erste Schritt in die Verderbnis 🙂 Du kommst in der Objektorientierten-Programmierung nämlich nicht ohne Referenzen aus, also müßtest du in diesem Fall auf Pointer zurückgreifen. Und damit wird nur alles verkompliziert. Falls dus kompliziert magst empfehle ich C++. Falls du schnell an dein Ziel kommen möchtest empfehle ich C# 😉 Vielleicht solltest du dich einfach näher mit der Objektorientierung vertraut machen. Du wirst sehen das alles seinen Sinn hat.

([bb]|[^b]{2})

Ingo Boller Themenstarter:in
14 Beiträge seit 2005
vor 19 Jahren

Ich sag es mal ganz kurz:
objektorientiert ist gekennzeichnet durch verschiedene Eigenschaften.

Ohne alle einzeln aufzuzählen fehlt bei
struct - Vererbung (Ableiten nicht möglich)
class - Kapselung (operator= und class.var=5; nicht möglich im Zusammenhang, wegen class=Referenz)

Und nun beweise mir gern das Gegenteil mit Sourcecode, denn das will ich wirklich wissen 😁 Ich lasse mich auch gern vom Gegenteil überzeugen.

C
980 Beiträge seit 2003
vor 19 Jahren

Objektorientierung ist ein Paradigma, nicht eine Eigenschaft einer Programmiersprache. Auch 86k Assembler oder C ermöglicht objektorientierte Programmierung (unterstützt* sie aber nicht), C++ unterstützt sie (unterstützt aber auch diverse andere Paradigmen), C# unterstützt sie nahezu exklusiv.

Auch wenn du nicht von Structs erben kannst, kannst du auf sie trotzdem die meisten Elemente des Paradigmas der Objektorientierung anwenden, z.b. das der Kapselung. Deine seltsame Interpretation des Zuweisungsoperators ändert auch nichts daran ... warum sollte ein Zuweisungsoperator etwas kopieren oder klonen? Wo ist das Problem mit Referenzen, ist doch eines der zentralen Elemente des Paradigmas, dass man mehrere Referenzen auf ein einzelnes Objekt halten kann, bei Bedarf sogar veralgemeinert -> Polymorphie

(*der Unterschied zwischen "ermöglichen" und "unterstützen" sollte klar sein..)

P
939 Beiträge seit 2003
vor 19 Jahren

struct - Vererbung (Ableiten nicht möglich)

Structs sind Wertetypen mit einer festgelegten Anordnung ihrer Datenfeldern, nicht mehr und nicht weniger. Man kann also sagen "Byte X im Struct S gehört zum Struct-Feld F".

Würde man Vererbung unterstützen wollen, müssten noch jede Menge Hilfsinformationen mit im Struct gespeichert werden. Damit würde der Datentyp inkompatiblen z.B. zum C-struct werden.

Man sollte froh sein, dass überhaupt Methoden unterstützt werden. Ist es etwa in C++ so, dass Wertetypen abgeleitet werden können oder wie kommst du sonst auf solche Ideen?

Gruss
Pulpapex

1.373 Beiträge seit 2004
vor 19 Jahren

Original von Ingo Boller
Bei string geht das auch nur so

  
string s1 = "    HALLO     ";  
string s2 = "   HUHU   ";  
s1.Trim();    // Hier passiert nichts !   
s1 = s1.Trim();   // jetzt wird s1 veraendert  
s1 = s2.Trim();  // s1 bekommt neue Instanz aus Funktion Trim() und s2 bleibt unveraendert  
  

in der letzten Zeile aendert sich s2 nicht

Also einfach keine (void) Funktionen mehr verwenden, die den inhalt einer Klasse selbst ändern.
Ist doch eigentlich ganz einfach 😄

Strings sind im .NET Framework unveränderlich. Das ist lediglich eine Entscheidung, die getroffen wurde. Aber das bedeutet nicht, dass man den inneren Zustand eines Objektes grundsätzlich nicht ändern darf. Jedesmal ein neues Objekt zu erstellen, dass die geänderte Version des Originals enthält ist in den aller meisten Fällen (wie gesagt, String ist die Ausnahme) totaler Unsinn. Kapselung bedeutet nicht, dass man sich der Zustand eines Objektes nicht ändern darf, sondern lediglich, dass er kontrolliert stattfindet (keine öffentlichen Felder usw.). .NET Klassen beherrschen die Säulen der Objektorientierung (Abstraktion, Kapselung, Vererbung und Polymorphie) vollständig.
Du bringst offenbar irgendwas ziemlich durcheinander...

MfG VizOne

Ingo Boller Themenstarter:in
14 Beiträge seit 2005
vor 19 Jahren

@cdr:
Es geht um unterstützen der Objektorientierung, so das man z.B. als Anwender einer Klasse nichts von deren Inhalt wissen muss.
Nun nochmal das Problem
**

  1. Schreibe eine C#-Klasse myclass mit einem int iWert drin.
  2. Setze iWert über set aus get/set Property Accessors // gutes Beispiel fuer Kapselung
  3. erstelle im Hauptprogramm zwei Instanzen von myclass mit Namen a und b
  4. setze a auf 1 und b auf 2
  5. a=b; // kann nicht gekapselt werden in c#
  6. setze a auf 5 (b bleibt 2)**
    Meine Folgerung daraus: Kapselung hat Schwächen bei Class wegen operator=
    Einzige Lösung bisher: Kapselung von iWert über set nicht verwenden, sondern
    public myclass setWert(int neuWert){return myclass(neuWert);}

@Pulpapex:
Mir ist schon klar wofür struct ist.

Ist es etwa in C++ so, dass Wertetypen abgeleitet werden können

Ja, in C++ ist eine Klasse ein Wertetyp, wobei man den Wertetyp intern, gekapselt auch als Referenz programmieren kann. Man kann es sich also selbst aussuchen wie die Klasse funktionieren soll, ohne das von außen etwas davon bemerkt wird. Man kann deshalb z.B. die interne Arbeitsweise auch nachträglich ändern ohne das Hauptprogramm anpassen zu müssen.

Ich bin nicht gegen C#. Ich fange gerade damit an und programmiere bisher seit 25 Jahren Assembler, Basic, C++ im Bereich Leckageüberwachungstechnik, CAD, Energie, Strahlungstechnik, Spiele, Bestriebssystemkernel, GUI, ...
C# gefällt mir bisher sehr gut (fragt mal meine Kollegen 🙂) C# flutscht eben noch nicht ganz so nach meinen ersten 5000 Zeilen wie man sieht. C# finde ich jedenfalls klarer als C++.

1.373 Beiträge seit 2004
vor 19 Jahren

Original von Ingo Boller

**

  1. Schreibe eine C#-Klasse myclass mit einem int iWert drin.
  2. Setze iWert über set aus get/set Property Accessors // gutes Beispiel fuer Kapselung
  3. erstelle im Hauptprogramm zwei Instanzen von myclass mit Namen a und b
  4. setze a auf 1 und b auf 2
  5. a=b; // kann nicht gekapselt werden in c#
  6. setze a auf 5 (b bleibt 2)**

Ich versuche es dir an Hand eines äquivalenten C++-Beispiels zu erklären:


MyClass * a = new MyClass(1); // C#: MyClass a = new MyClass(1)
MyClass * b = new MyClass(2); // C#: MyClass b = new MyClass(1)

a = b; 
// a->getData() == b->getData()
a->setData(5); 
// noch immer: a->getData() == b->getData()

Abgesehen davon, dass der Code in dieser Form natürlich ein Memoryleak hat, ist es doch wohl offensichtlich, dass a und b das gleiche Objekt ansprechen, wenn man b an a zuweist. Das hat nichts mit (fehlender) Kapeslung zu tun.
C# benutzt bei Referenztypen implizit(!) "Zeiger", ohne dass man * schreiben müsste. Ansonsten passiert genau das gleiche - wenn man zwei Referenzen ("Zeiger") eine Referenz auf das selbe Objekt zuweist, sind Änderungen von beiden Referenzen aus sichtbar.

Meine Folgerung daraus: Kapselung hat Schwächen bei Class wegen operator=
Einzige Lösung bisher: Kapselung von iWert über set nicht verwenden, sondern
public myclass setWert(int neuWert){return myclass(neuWert);}

Es besteht keine Schwäche in der Kapselung. Das einzige, was etwas verwirrend sein kann, ist, dass mehrere Referenzen auf das gleiche Objekt zeigen (Aliasing) - das Problem gibt es aber in C++ genauso.

Ich bin nicht gegen C#. Ich fange gerade damit an und programmiere bisher seit 25 Jahren Assembler, Basic, C++ im Bereich Leckageüberwachungstechnik, CAD, Energie, Strahlungstechnik, Spiele, Bestriebssystemkernel, GUI, ...

Logischerweise fällt es dann zunächst schwer, von bestehendem Wissen zu lösen neue Konzepte zu begreifen.

Also, noch einmal - ein Referenztyp in C# wird immer über eine Referenz angesprochen. Eine Referenz ist vergleichbar mit einem C++-Zeiger (nachträgliche Zuweisung und null-Zuweisung möglich), sie wird lediglich vom Garbage Collector überwacht.


C#:
MyClass a = new MyClass();
C++
MyClass * a = new MyClass();

MfG VizOne

Ingo Boller Themenstarter:in
14 Beiträge seit 2005
vor 19 Jahren

Vielen Dank für die rege Beteiligung. Ich habe eigentlich schon die passenden Antworten erhalten. Aber weil es so spannend ist kann ich nicht aufhören 🙂

@ VizOne

Jedesmal ein neues Objekt zu erstellen, dass die geänderte Version des Originals enthält ist in den aller meisten Fällen (wie gesagt, String ist die Ausnahme) totaler Unsinn

Ist klar, deshalb nimmt man bekanntlich eine konstante referenz als Übergabeparameter in c++.
fkt(const myclass &instanz)
Wie macht man das in c# ?
Oder muß man innerhalb der fkt selbst aufpassen ?

Kapselung bedeutet nicht, dass man sich der Zustand eines Objektes nicht ändern darf, sondern lediglich, dass er kontrolliert stattfindet

Wie macht man denn eine kontrollierte Änderung innerhalb einer Klasse, wenn zwei referenzen auf ein im Speicher befindliches Object vorliegt ? Oder was meinst Du mit Kapselung und kontrolliert ?

.NET Klassen beherrschen die Säulen der Objektorientierung (Abstraktion, Kapselung, Vererbung und Polymorphie) vollständig

Hast Du gerade eine .NET Klasse parat, an der ich das ausprobieren kann ?
Also eine, die nur sich intern ändert durch z.B. eine void fkt ?

Du bringst offenbar irgendwas ziemlich durcheinander...

Schnüff, aber etwas Ahnung habe ich aber auch 😭

P
939 Beiträge seit 2003
vor 19 Jahren

4) setze a auf 1 und b auf 2
5) a=b; // kann nicht gekapselt werden in c#
6) setze a auf 5 (b bleibt 2)

Die Variable b wird in dem Fall auch 2. Liegt daran, dass a und b nach der Zuweisung die selbe Instanz halten. Allerdings, die Instanz, die vor der Zuweisung in a war, ist immer noch 1. Sollte auch so zu erwarten sein, es sind ja zwei Instanzen.

Worauf du wahrscheinlich hinaus möchtest, sind Referenzen auf Referenzen. Man hat zwei Variablen a und b und wenn man b auf einen neuen Wert ändert, ändert sich auch a. Sowas geht in C# tatsächlich nicht (mangels eines Zeigertyps). Man kann es nur mit zwei Objekten, wo das erste Objekt als Referenz auf das zweite Objekt dient, nachbilden.

Mit Methoden-Parametern ist es dann doch wieder möglich. Übergibt man ein Objekt über einen ref-Parameter und wird der Parameter in der Methode auf eine neue Instanz geändert, ändert sich auch die Variable in der aufrufenden Methode.

public void Caller() {
  object a = "test";
  Callee(ref a);
  // a == "geändert";
}

public void Callee(ref object s) {
  s = "geändert";
}
1.373 Beiträge seit 2004
vor 19 Jahren

Original von Ingo Boller

Du bringst offenbar irgendwas ziemlich durcheinander...
Schnüff, aber etwas Ahnung habe ich aber auch 😭

Entschuldige, war etwas unglücklich formuliert. 😉

MfG VizOne

P
939 Beiträge seit 2003
vor 19 Jahren

Jetzt weiss ich was du meinst. Du möchtest genau den Fall haben, dass sich Variablen trotz Zuweisung nicht gegenseitig die Werte ändern. Tja, da kann ich nur sagen, das Ding nennt sich Referenztyp. Das muss man einfach so hinnehmen, dass bei der Zuweisung eines Referenztypes keine Kopie erstellt wird.

Wenn man kopieren möchte, muss die Klasse eine Methode dafür anbieten, Stichwort: ICloneable-Interface. Eine flache Kopie erhält man über die geschützte Object.MemberwiseClone-Methode. Die dürfte in etwa dem Kopieren von C++ Klassen entsprechen.

public class Kopierbar : ICloneable {

  public object Clone() {
    return this.MemberwiseClone();
  }
}

// Anwendung.
Kopierbar a = new Kopierbar();
Kopierbar b = (Kopierbar)a.Clone();
Ingo Boller Themenstarter:in
14 Beiträge seit 2005
vor 19 Jahren

Original von VizOne

Ich versuche es dir an Hand eines äquivalenten C++-Beispiels zu erklären:

  
MyClass * a = new MyClass(1); // C#: MyClass a = new MyClass(1)  
MyClass * b = new MyClass(2); // C#: MyClass b = new MyClass(1)  
a = b;   
// a->getData() == b->getData()  
a->setData(5);   
// noch immer: a->getData() == b->getData()  
  

Abgesehen davon, dass der Code in dieser Form natürlich ein Memoryleak hat, ist es doch wohl offensichtlich, dass a und b das gleiche Objekt ansprechen, wenn man b an a zuweist. Das hat nichts mit (fehlender) Kapeslung zu tun.

Ja das ist klar. So funktioniert das.
Unabhängig von C# sähe eine Lösung in C++ aber anders aus, etwa so:

MyClass a(1);
MyClass b(2);
a=b;
a.setData(5);  // oder besser a=5;

Jetzt hängt es von der Implemetierung der Klasse ab, ob Zeiger verwendet werden. Einige bekannte c++Klassen verwenden smart pointer bei a=b. a und b zeigen auf den gleichen int mit wert 1. Weiterhin hat das intern referenzierte int-object einen Referenzzaehler. Wenn also beide nicht mehr darauf zeigen wird der Speicher freigegeben.
Mit der Anweisung a.setData(5) oder besser a=5; wird nun eine neuer int mit 5 erzeugt und a zeigt darauf. A hat seinen Referenzzaehler danach auf 1 und b seinen eigenen Referenzzähler auch auf 1 (vorher 2).
Das ist schnell da nicht dauernd neue Objecte angelegt werden muessen. (Nur der Pointer wird gesetzt und ein Referenzzaehler mitgeführt)
Es ist vollständig gekapselt, da man es sich aussuchen kann ob immer mit Referenz gearbeitet wird, oder nur bis zur nächsten Änderung.
In C# kann man es sich nicht aussuchen

Wer das Gegenteil beweisen kann, der konvertiert bitte das obige Beispiel in C# unter Verwendung von class ?
Ich habe bisher gelernt das das nicht geht. Und viele nette Leute haben das auch nochmal wiederholt.

BTW: War nicht mal vor langer Zeit der C-Pointer total negativ behaftet ? So ändern sich die Zeiten ! Es gibt doch dieses Beipiel "Wie fängt man einen Elefanten ?" -> SQL: Select Elefant from Afrika etc.

Ich kann damit leben, aber Wünsche bleiben für den C#-Nachfolger.

Es ist auf jeden Fall nicht einfach c++-Projekte nach c# zu konvertieren. Deshalb habe ich auch schon erlebt das c# abgelehnt wurde. Mal abgesehen davon, dass unter Windows auch die API geändert ist.
Ich bereite gerade ein neues Projekt für meine Kollegen und mich vor und das wird mit 99 % Sicherheit in c# abgewickelt.

Also nochmal Danke an Alle !!!!!!

1.373 Beiträge seit 2004
vor 19 Jahren

Dein gesamtes Problem lässt sich auf einen Fakt reduzieren: Es gibt keinen Zuweisungsoperator in C# der Referenztypen kopiert (statt nur die Referenzen selbst zu kopieren) - dafür wird in .NET nun mal Clone verwendet, um den Vorgang deutlich zu machen.

Alles andere (Copy-on-write Semantik, Referenzzählung usw), was du angesprochen hast, lässt sich auch mit C# machen.

Hier ein einfaches Beispiel für Copy-on-write (nicht ganz vollkommen, ein shared core wird nicht auf unshared gesetzt, wenn nur noch eine MyClass-Instanz darauf zeigt - das ist aber nicht tragisch)


public class MyClass : ICloneable {

	class Core {
		private int data;

		public Core() {
			Console.WriteLine( "Neuer Core" );
		}

		public int Data {
			get { return data; }
			set { data = value;}
		}
	}

	private Core core;
	private bool sharedCore;

	public MyClass() : this(0) {
	}

	public MyClass(int data) {
		core = new Core();
		core.Data = data;
		sharedCore = false;
	}


	public int Data {
		get { return core.Data; }
		set {
			// copy on write
			if ( sharedCore ) {
				core = new Core();
				core.Data = value;
				sharedCore = false;
			} else {
				core.Data = value;
			}
		}
	}

	object ICloneable.Clone() {
		return Clone();
	}

	public MyClass Clone() {
		// shallow copy, referenz(!) kopieren
		MyClass clone = (MyClass)MemberwiseClone();
		// unser core ist jetzt in jedem fall geteilt
		sharedCore = true;
		clone.sharedCore = true;
		return clone;
	}
}

class Program {
	public static void Main() {
		MyClass a = new MyClass( 5 );
		MyClass b = new MyClass( 2 );
		a = b.Clone();
		Console.WriteLine( a.Data );
		Console.WriteLine( b.Data );
		a.Data = 7; // copy on write! 
		Console.WriteLine( a.Data );
		Console.WriteLine( b.Data );

		Console.ReadLine();
	}
}

Der einzige Unterschied ist hier, dass Clone benutzt wird statt einer Zuweisung mittels =.

MfG VizOne

[edit]Hier die Ausgabe:
Neuer Core
Neuer Core
2
2
Neuer Core
7
2
[/edit]

[edit2]
OK, Referenzzählung ist etwas ungünstig in .NET auf Grund der nicht-deterministischen Zerstörung von Objekten - allerdings sollte man eh nicht versuchen krampfhaft alle Techniken aus der nativen C++ Welt in die .NET Welt zu übernehmen. Man muss versuchen, Probleme auf die .NET Art zu lösen.
[/edit2]

49.485 Beiträge seit 2005
vor 19 Jahren

Hallo Ingo,

Ich kann damit leben, aber Wünsche bleiben für den C#-Nachfolger.

Zumindest was die Verweissemantik angeht "works C# as designed". Deine Wünsche werden sich nicht erfüllen. Und wie die div. Beiträge zeigen, gibt es dafür gute Gründe.

Es ist auf jeden Fall nicht einfach c++-Projekte nach c# zu konvertieren.

Das hängt von den Projekten ab. Ich habe in keinem meiner Projekt C++-Variablen so benutzt:


MyClass a(1);

sondern immer so


MyClass *pa = new MyClass (1);

weil ich wusste, dass die Wertsemantik der C-Variablen eine von C geerbte Schwäche von C ist!

Der Punkt ist der: Sicher gibt es (unabhängig von der Programmiersprache) einige Objekte mit Wertsemanik: Int, String, Point, Rectangle. Aber der Kern der Objektorientierung sind Objekte mit Id: Kunde, Auftrag, Konto, aber auch TextBox und Form. Also Objekte, die es jeweils nur einmal gibt. Es gibt sie in der realen Welt nur einmal - also ich meine jetzt z.B. den einen bestimmten Kunden, dann soll es ihn im Modell nur einmal geben und in der Implementierung nur einmal geben. So ein Objekt zu kopieren läuft der Intention entgegen. Zwei mal derselbe Kunde? Wie soll das gehen? (Ok, aus Versionierungsgründen, aber das ist ein anderes Thema, das man anders lösen kann und sollte). Deshalb ist es genau richtig, dass hier mit Verweisen gearbeitet wird, denn Gründe von verschiedenen Stellen auf denselben Kunden zuzugreifen kann und wird es natürlich geben.
Auch für die Klasse Form wäre a = b; mit Wertsemantik verheerend; habe ich das Fenster dann zweimal auf dem Schirm? Nee, will man nicht. Auch hier ist Verweissemantik gewünscht.

Ich hoffe, ich konnte klar machen, warum Verweissemantik bei Variablen ein sinnvolles Feature von C# ist und gerade Highlevel-Programmierung darstellt und ermöglicht.

herbivore