Autor Beitrag
Nuckey
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78



BeitragVerfasst: Do 28.04.11 15:59 
unter bestimmte bedingung kommt diese fehlermeldung ; Der Rückgabewert "Sacred2Ed._Surface.this[uint]" kann nicht geändert werden, da er keine Variable ist.


dieser fehler kommt nicht mehr , wenn ich struct in class umschreibe

ich denke es mir so ,da struct werte typen sind und auf dehm stack generiert werden aber der rückgabetype vom ort heap ausgeht,so das die struct surface "nicht sichtbar" ist.

liege ich da ungefähr richtig ??


eine weiter frage betrift die initialliesierung von _Surfaceid[],da ich hier in einer schleife nochmals die arrays mit new alloc. werden


kann mir jemand tips geben ??

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
public struct _SurfaceID
    {
        private string surfaceID0;
        private string surfaceID1;

        public string SurfaceID0
        {
            get { return this.surfaceID0; }
            set { this.surfaceID0 = value; }
        }

        public string SurfaceID1
        {
            get { return this.surfaceID1; }
            set { this.surfaceID1 = value; }
        }
    }

    public class _Surface
    {
        private _SurfaceID[] surface = new _SurfaceID[8];

        public _Surface()
        {
            for (int x = 0; x < 8; x++)
                surface[x] = new _SurfaceID();

        }

        public _SurfaceID this[UInt32 index]
        {
            get { return surface[index]; }
            set { surface[index] = value; }
        }



    }


    public class _Model0Data
    {

        private string name;
        private string user;

        public string Name
        {
            get { return this.name; }
            set { this.name = value; }
        }

        public string User
        {
            get { return this.user; }
            set { this.user = value; }
        }


        public _Surface Surface = new _Surface();
    }





mfg nuckey

Moderiert von user profile iconChristian S.: Code- durch C#-Tags ersetzt
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19339
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 28.04.11 16:11 
Nicht ganz, das Problem ist einfach, dass eine Struct als Wert abgerufen wird. Das heißt du hast eine Kopie der Daten. Wenn du also daran etwas ändern würdest, würde sich das nicht auf die Originaldaten auswirken. Der Compiler ist schlau genug das zu erkennen und abzufangen. ;-)

Eine class, also ein Objekt, wird hingegen als Referenz abgerufen. Du greifst also auf das Originalobjekt zu und änderst dieses.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 28.04.11 16:14 
Zitat:
ich denke es mir so ,da struct werte typen sind und auf dehm stack generiert werden aber der rückgabetype vom ort heap ausgeht,so das die struct surface "nicht sichtbar" ist.


Nö der struct ist Member einer class und der struct liegt damit dort wo auch die class liegt also vermutlich auf dem Heap. Wo genau ist aber letztlich auch völlig irrelevant.

Problem ist das du auf den struct über eine Property zugreifst. Und da structs Wertetypen sind erhältst du eine Kopie. Die zu ändern wäre also ziemlich sinnfrei. Wenn du einen Typen zur Laufzeit ändern willst(ohne Kopie) ist ein Referenztyp(class) sinnvoller. Wenn es ein Wertetyp bleiben muß (warum auch immer) darfst du nicht über eine Property drauf zugreifen sondern mußt direkt auf das Feld zugreifen(also surface in _Surface public machen).
IsNull
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 97
Erhaltene Danke: 11


VS 2010, C#, AHK
BeitragVerfasst: Do 28.04.11 16:16 
ausblenden C#-Quelltext
1:
2:
for (int x = 0; x < 8; x++)
      surface[x] = new _SurfaceID();

Was erhoffst du dir davon? Wenn der Array initialisiert wird, werden bei Werte Typen automatisch der Default Constructor aufgerufen, structs sind nie 'null' ;)

ausblenden C#-Quelltext
1:
_SurfaceID[] surface = new _SurfaceID[8];					

Reicht vollkommen ;)
Nuckey Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78



BeitragVerfasst: Do 28.04.11 16:32 
danke erst mal an alle habe struct in class umgewandelt und funzt so wie es soll:

@ isnull : ist so nicht richtig (so wies sich hir bei mir zeigt),es wird zwar array angelegt mit 8 felder ,aber dise sind mit inhalt null.

um aber auf die struct/class _SurfaceID zuzugreifen muss ich defakto eine refernz an die arrayfelder übergeben

um zb so zugreifen zu können  tmpitemtype.model0data.Surface[0].SurfaceID0 = "help";

wenn ich es nicht mache meckert der compiler ;)

denn in prinzip ist es ein array mit zeiger auf dehm typ SurfaceID



mfg nuckey
Yogu
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: Do 28.04.11 17:37 
user profile iconNuckey hat folgendes geschrieben Zum zitierten Posting springen:
danke erst mal an alle habe struct in class umgewandelt und funzt so wie es soll:

@ isnull : ist so nicht richtig (so wies sich hir bei mir zeigt),es wird zwar array angelegt mit 8 felder ,aber dise sind mit inhalt null.

Witzbold, erst schreibst du, dass du Structs hast, weshalb user profile iconIsNull seinen korrekten Vorschlag macht - und dann änderst du die Structs in Klassen um und sagst, er hätte nicht recht ;)

Klassen müssen mit Konstruktoren erstellt werden, denn sie sind mit null initialisiert. Für Structs muss man keinen Konstruktor aufrufen, denn ihre Instanzen werden automatisch instanziert.

Die Daten von Klassen liegen als separate Blöcke im Speicher und sind unabhängig von ihren Referenzen. Über eine Variable wird auf diesen Speicherblock zugegriffen, weshalb er für alle Referenzen gilt. Structs dagegen lagern ihre Daten direkt in der Variable ab. Wird auf eine Struct-Variable zugegriffen, wird nur sie selbst geändert. Sie können außerdem (fast) immer nur komplett zugewiesen werden (die Eigenschaften können nicht verändert werden), da sie in der Regel immutable, also unveränderlich, sind.

Jetzt musst du entscheiden, ob du eine Struct oder eine Klasse brauchst, und den Code entsprechend anpassen.
Nuckey Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78



BeitragVerfasst: Do 28.04.11 17:52 
@ Yogu: nun ich kann erstmal nur von dehm ausgehen was ich hier beobachte (mein program)

und er reagiert so wie ich es beschreibe ,ich muss nochmal per new _SurfaceID instanzieren ,sei es struct oder classe

ansonsten gib es eine fehlermeldung wegen null instanz.


edit:


habe es nochmal dehn betrefenden code herausgenommen und für sich getestet ohne eigenschaftengedöns


jo Isnull und Yogie hatte diesbezüglich recht ;)


aaaargh ! sry ;)

mfg nuckey
Einloggen, um Attachments anzusehen!


Zuletzt bearbeitet von Nuckey am Do 28.04.11 18:11, insgesamt 1-mal bearbeitet
IsNull
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 97
Erhaltene Danke: 11


VS 2010, C#, AHK
BeitragVerfasst: Do 28.04.11 18:08 
Schau nochmal genau nach was null ist, wenn du struct _SurfaceID nutzt. ;)

Was evtl passiert ist, dass der string im _SurfaceID-struct null ist. Obwohl ein string ebenfals ein value type ist, kann der null sein. Das ist etwas verwirrend, aber that's it. Keine Regel ohne Ausnahme.
ausblenden C#-Quelltext
1:
2:
string str1;
string str2 = "";


--> str1 ist null, str2 ist ein leerer string. Wenn du auf Members von str1 zugreifst, wirst du eine NullRef-Exception bekommen.
Yogu
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: Do 28.04.11 18:10 
Vielleicht haben wir etwas an einander vorbei geschrieben.

Ich würde vorschlagen, _Surface auf jeden Fall als Klasse zu belassen, da der Typ ein Array enthält. Structs mit Arrays sind nicht schön.

_SurfaceID sieht so aus, als würde ein Struct gut passen, da er nur zwei Strings speichert. Allerdings solltest du diesen unveränderlich machen, also die Setter der Eigenschaft entfernen. Wenn eine Variable dieses Typs geändert werden soll, muss sie dann neu zugewiesen werden. In diesem Thema findest du eine Erklärung, warum das besser ist.

Da _SurfaceID nun ein Struct ist, kannst du den Konstruktor von _Surface in Zeile 23 so verkürzen wie user profile iconIsNull geschrieben hat. Das Array muss aber auf jeden Fall initialisiert werden, denn es selbst kann null sein.

Ich würde übrigens die Unterstriche von den Klassennamen entfernen - das ist auf die Dauer doch etwas nervig zu schreiben.

Grüße,
Yogu
Nuckey Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78



BeitragVerfasst: Do 28.04.11 18:14 
habe dehn betreffen code herausgenommen und für sich getestet ohne eigenschaftengedöns



uuuuuuuund sry ihr beide hattet diesbezüglich recht die struct wird instanziert ;)


autsch ;)


jo yougu werde bei der klasse bleiben sonst gibte es wieder mekker wegen siehe thread
danke noch mal


na ja mit dehm unterstrich hat sich so eingebürgert



mfg nuckey
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4807
Erhaltene Danke: 1061

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 29.04.11 10:07 
Hallo IsNull,

IsNull hat folgendes geschrieben:

Obwohl ein string ebenfals ein value type ist, kann der null sein. Das ist etwas verwirrend, aber that's it.

Es ist genau andersherum. Ein String ist eine Klasse (d.h. ein Referenztyp), verhält sich aber wie ein Werttyp, da die Klasse als 'immutable' implementiert ist, s. z.B. Besonderheiten der String-Klasse (immutabler Referenztyp mit Wertsemantik)

Und daher spielt es auch performance-technisch kaum eine Rolle, ob man eine Struktur oder eine Klasse erstellt, welche nur aus Strings besteht, da hier eben nur Referenzen gehalten werden.

Die Entscheidung für oder gegen eine Struktur sollte entsprechend der Erwartung (reine Datenklasse), gewählt werden, s. www.diranieh.com/NET..._and_Reference_Types


Zuletzt bearbeitet von Th69 am Fr 29.04.11 14:27, insgesamt 1-mal bearbeitet
Yogu
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: Fr 29.04.11 12:15 
user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Und daher spielt es auch performance-technisch kaum eine Rolle, ob man eine Struktur oder eine Klasse erstellt, welche nur aus Strings besteht, da hier eben nur Referenzen gehalten werden.

Unabhängig davon, ob du damit meine Empfehlung kritisieren wolltest, möchte ich die Gelegenheit ergreifen, diese nochmal zu erklären. Der Typ _SurfaceID verbindet die zwei Strings SurfaceID0 und SurfaceID1 zu einem Objekt, so ähnlich wie ein Typ "VollständigerName" die Strings "Vorname" und "Nachname" verbinden könnte, oder ein Typ "Bruch" den "Zähler" und den "Nenner". Bei den beiden Beispielen dürfte wohl ziemlich klar sein, dass ein Struct die bessere Wahl wäre. Wenn der Typ _SurfaceID nun wirklich einfach zwei IDs zu einer ID zusammenfasst, sollte dort auch ein Struct verwendet werden.

user profile iconNuckey hat folgendes geschrieben Zum zitierten Posting springen:
jo yougu werde bei der klasse bleiben sonst gibte es wieder mekker wegen siehe thread

Ich hatte dir bereits einen Weg gezeigt, wie du beim Struct bleiben kannst, ohne die Fehlermeldung zu bekommen:

user profile iconYogu hat folgendes geschrieben Zum zitierten Posting springen:
_SurfaceID sieht so aus, als würde ein Struct gut passen, da er nur zwei Strings speichert. Allerdings solltest du diesen unveränderlich machen, also die Setter der Eigenschaft entfernen. Wenn eine Variable dieses Typs geändert werden soll, muss sie dann neu zugewiesen werden. In diesem Thema findest du eine Erklärung, warum das besser ist.

Structs sollten schlicht und einfach immer unveränderlich sein. Dann kannst du solche Fehlermeldungen wie "Der Rückgabewert kann nicht geändert werden, da er keine Variable ist." gar nicht bekommen, da der Rückgabewert ja überhaupt keinen Setter besitzt. Und stattdessen einen Konstruktor aufzurufen, um den Wert des Indexers neu zuzuweisen, ist ja nicht so viel Aufwand.
Nuckey Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78



BeitragVerfasst: Fr 29.04.11 14:15 
dank dir für die mühe Yogu:

muss mir erst dehn artikel übesetzen lassen ,da mein englisch fast null ist ;)

werd die sache in ruhe am wochenende angehn

mfg nuckey
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Fr 29.04.11 19:24 
user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
verhält sich aber wie ein Werttyp, da die Klasse als 'immutable' implementiert ist

user profile iconYogu hat folgendes geschrieben Zum zitierten Posting springen:
Bei den beiden Beispielen dürfte wohl ziemlich klar sein, dass ein Struct die bessere Wahl wäre.


Um mal einen Bogen zum anderen Thread zu schlagen, wiederhole ich schnell meine Meinung ;) : Da es keinen semantischen Unterschied zwischen immutablen Structs (und das sollte wie erwähnt auf alle zutreffen) und immutablen Klassen gibt, ist Performance der einzige Grund, Structs einzusetzen - und zwar weder ein gewichtiger noch ein überhaupt oft zutreffender, also sind Klassen nie eine falsche Wahl.

@Th69: Ich will eigentlich nicht schon wieder eine deiner Quellen kritisieren :D , aber nach dem Satz "Allocating a large number of reference types fragments the heap" ist mir der Artikel ein wenig suspekt.

_________________
>λ=
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4807
Erhaltene Danke: 1061

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Sa 30.04.11 11:35 
Hallo Kha,

endlich mal eine Diskussion :lol:

Ich bin natürlich nicht immer 100-prozentig mit allen Aussagen der von mir verlinkten Seiten einverstanden, aber ich finde es wichtig, verschiedene Meinungen zu einem Thema einzuholen und dann selber darüber nachzudenken.

Bei dem von dir zitierten Satz stimme ich dir zu, daß dieser nicht so ganz (in der Managed-Welt) in Ordnung ist, d.h. es fehlen noch weitere Erklärungen.

Hier erstmal noch weitere Links zum Thema "Stack vs. Heap" und "Heap Fragmentierung":
www.c-sharpcorner.co...m/csharp_memory.aspx (Part I - Part IV)
cplus.about.com/od/learnc/ss/value.htm
www.codeguru.com/col...et/article.php/c6593
theburningmonk.com/2...the-memory-pitfalls/

stackoverflow.com/qu...t-heap-fragmentation

Man sollte also wissen, wie der Managed-Heap verwaltet wird und welche Aufgaben der GC erledigt, um einer möglichen Fragmentierung entgegenzuwirken. Nichtsdestotrotz kann es aber bei einem Heap immer leichter zu eine Fragmentierung kommen als eben bei einem Stack.
(So schlimm wie bei einem nativen (nicht-managed) Programm, das nur den System-Heap benutzt und keinen GC kennt, ist es aber bei weitem nicht.)

Mir ging es ja aber auch gar nicht um diese Aspekt, sondern um die von mir geschriebene Benutzung als reine (und kleine!) Datenklasse (um sich für eine Struktur zu entscheiden).

Und deine Aussage bzgl. 'immutable struct' kann ich zwar als Forderung nachvollziehen, in der Praxis scheint dies aber nicht immer umgesetzt zu werden, z.B. für die häufig verwendeten Strukturen 'System.Drawing.Point' und 'System.Drawing.Rect' (welche beide eben nicht unveränderlich(immutable), sind).
Und mir selber sind auch häufig Strukturen der Art
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
struct MyStruct
{
  public int x;
  public int y;
  public int z;
}

o.ä. begegnet, d.h. einfache öffentliche Felder, anstatt nur Konstruktor(en) und Getter-Eigenschaften (auch wenn dies wohl evtl. eher von ehemaligen C- bzw. C++-Programmierern kommt, welche evtl. noch nicht den Unterschied von 'struct' und 'class' in C# (.NET) kennen.)

So genug geschrieben ;-)

Gruß
Th69

P.S. Ich finde die ganze Seite www.diranieh.com/ sehr gut gemacht. Es gibt auch noch Part II: www.diranieh.com/NET.../EffectiveCSMore.htm

Und noch ein P.S.: Paßt zwar eher in den anderen Thread, aber hier steht es mal explizit, daß Wertetypen (d.h. auch Strukturen) innerhalb von Klassen natürlich auch auf dem Heap alloziert werden: csharp.2000things.co...e-types-on-the-heap/
Nuckey Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78



BeitragVerfasst: Sa 30.04.11 12:38 
dank dir th69 für die zusatzinfos

habe mir das ganze angeschaut über das thema immutable struct.

na ja so ganz glücklich bin ich nicht über diese immutable lösung,da es anscheinend (soweit ich es aus der übersetzung entnehmen konnte) querellen mit propertygrid gibt und ich dieses aber einsetzen wollte .

werde aber diese sache weiterverfolgen ,bleibe aber jetze erstmal bei der class lösung ,da bequemer ;)

und da die sache eh aufn heap fällt ,macht die for next schleife dehn kohl auch nicht mehr fett,

bin aber am überlegen die for/nextschleife aufzurollen,da sich die anzahl der arrayfelder nicht ändert.

werde mal mich umsehen nach vernünftiger dokumentation ,was sich mit dehn themen tiefer beschäftigt.

mfg nuckey
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Sa 30.04.11 13:57 
user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
endlich mal eine Diskussion :lol:
Wenn wir uns genügend anstrengen, werde ich sie sogar abtrennen :mrgreen: .

user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Nichtsdestotrotz kann es aber bei einem Heap immer leichter zu eine Fragmentierung kommen als eben bei einem Stack.
Den LOH habe ich mal außen vor gelassen; ohne ihn sehe ich keinen Unterschied zwischen einem linearen Heap und einem Stack :gruebel: .
Aber eigentlich wollte ich damit nur meine Bedenken einwerfen, ob der Autor beim Schreiben wirklich an die richtige Plattform gedacht hat. In Delphi wäre der Satz "Structs store data. Classes define behavior. " sicher besser aufgehoben (und bei C++ ist sowieso wieder alles anders ;) ), ich sehe jedenfalls immer noch keine einzige Begründung, warum er für die CLR zutreffen sollte. Noch schlimmer, wenn man deswegen die zutreffenden Best Practices in den Wind schlägt:
Zitat:
The documentation for .NET recommends that you consider the size of a type as a determining factor between value types and reference types. In reality, a much better factor is the use of the type.



user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Und deine Aussage bzgl. 'immutable struct' kann ich zwar als Forderung nachvollziehen, in der Praxis scheint dies aber nicht immer umgesetzt zu werden, z.B. für die häufig verwendeten Strukturen 'System.Drawing.Point' und 'System.Drawing.Rect' (welche beide eben nicht unveränderlich(immutable), sind).
Für die zwei dürfte es nur einen Grund für die Mutability geben: Marshalling zu GDI+. Würdest du selbst denn einen CLR-internen Point-Typ nicht immutable machen? Eric Lippert würde es jedenfalls, nehme ich einfach mal an ;) .

Und ein Gegenbeispiel, das etwas moderner als 1.0 ist: System.Tuple dürften wohl die Musterbeispiele von reinen, kleinen Datenklassen sein, aber trotz Immutability sind es Klassen - weil das F#-Team riet, dass sie so performanter sein dürften. Das bezieht sich wahrscheinlich auf den Fakt, dass Structs, die Referenzen enthalten, bei jeder Zuweisung eine Memory Barrier auslösen.

user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
o.ä. begegnet, d.h. einfache öffentliche Felder, anstatt nur Konstruktor(en) und Getter-Eigenschaften
Was soll ich damit, das kann ich ja nichtmal an WPF binden :mrgreen: ?

_________________
>λ=