![]() |
[C#] Dies ist keine Variable?
Ich fummel gerade mit C# rum, und da kam mir etwas seltsames über den Weg:
Ich habe folgenden Struct:
Code:
Und von diesem eine Liste "List<MarkedPoint>" in meiner Klasse als privates Feld. Innerhalb dieser Klasse gibt's so eine Methode:
public struct MarkedPoint
{ public int X; public int Y; public bool Marked; public MarkedPoint(int posX, int posY, bool marked) { X = posX; Y = posY; Marked = marked; } public MarkedPoint(int posX, int posY) { X = posX; Y = posY; Marked = false; } }
Code:
(Das ist natürlich ein auf die für die Frage essentiellen Teile herunter gebrochenes Codebröckchen ;))
private void DoSomething(ref List<MarkedPoint> e)
{ if (e.Count>2) { int i = 1; do { if (eineBedingung) e[i].Marked = true; i++; } while (i<e.Count-1); } } Diese rufe ich dann aus einer anderen Methode heraus auf, die den Parameter aus einer übergeordneten Liste "List<List<MarkedPoint>> MainList" via "DoSomething(ref MainList[k])" in einer Schleife über k übergibt. Das Problem: Bei der Zuweisung [i]"if (eineBedingung) e.Marked = true;" meldet #Develop: "Cannot modify the return value of 'System.Collections.Generic.List<Class1.MarkedPoin t>.this[int]' because it is not a variable (CS1612)" Warum zum Henker?? Ändern des Parameters in "out" statt "ref" bringt das selbe Ergebnis. Ich komm nicht dahinter, und zudem brauch ich da sowas wie ne Lösung für :? |
Re: [C#] Dies ist keine Variable?
Ganz einfach: der linken Seite kann nichts zugewiesen werden bzw. anders gesagt: ihr könnte zwar theoretisch etwas zugewiesen werden, da dieser Wert aber temporär wäre macht es keinen Sinn ihm etwas zuzuweisen. Mit anderen Worten: e[i] liefert dir eine lokale Kopie des Structs an der i-ten Stelle von e. Wenn du diese Kopie änderst ändert das aber natürlich nichts am entsprechenden Struct in der Liste. Mit der Liste ist das etwas umständlich zu lösen (altes Item lokal kopieren, aus der Liste löschen, Marked setzen und dann wieder an der richtigen Stelle einfügen). Besser wäre hier allerdings ein Array - auf das könntest du direkt zugreifen und die Werte ändern.
//EDIT: Wieso übergibst du eigentlich die Liste mit ref? Da es sich um ein Objekt handelt wird ohnehin nur ein "Zeiger" übergeben - das ref kannst du dir also sparen. Dust Signs |
Re: [C#] Dies ist keine Variable?
Das ref ist drin, weil ich sowas wie du für das einzelne Feld beschrieben hast, für die ganze Liste befürchtet habe :) Ich tu mich noch etwas schwer damit, wann und wo genau C# jetzt mit kopien und wo mit Verweisen arbeitet. Somit ist wenigstens klar, dass die Methode diesen Parameter verändert.
Das mit der lokalen Kopie ist ärgerlich. Arrays will ich ungern benutzen, da ich die in List implementierten anderen Methoden ausgiebig nutze. Ich hab mir jetzt so beholfen:
Code:
Die Zuweisung einer ganzen neuen Instanz klappt nämlich. Leidet zwar ein wenig die Geschwindigkeit (und der GC) drunter, aber ich bin noch lange nicht in der Optimierungsphase. Da nehm ich die paar ms noch in Kauf.
e[i] = new MarkedPoint(e[i].X, e[i].Y, true);
Danke für die Erläuterung! (Auch wenn ich meine, dass mir die Liste da ja mal ruhig ne ordentliche Referenz ausspucken dürfte... grml) |
Re: [C#] Dies ist keine Variable?
Zitat:
|
Re: [C#] Dies ist keine Variable?
Ich hatte zu allererst mit Klassen gearbeitet, da ich aber pervers oft irgendwo Punkte neu erzeuge und wieder lösche, und teils hunderte Elemente lange Teil-Listen auf den Kopf stelle und aneinander pappe und noch andere wilde Digne damit anstelle, hab ich mit vertretbarem Aufwand (=ich will da in der jetzigen Phase möglichst kaum Hirnschmalz reintun) keine akzeptablen Laufzeiten hinbekommen. Sobald ich aus dieser "Proof-of-Concept" Phase raus bin, muss ich aber eh noch einiges optimieren und neu schreiben - ich muss halt aber erst noch raus finden, ob sich die Arbeit in ein ordentliches Programm wirklich nachher lohnt. Solang ich im Moment effizient testen kann bin ich erstmal glücklich.
Aber ich werd zu gegebener Zeit schauen ob sich da ein gutes Klassen-Konzept zu finden lässt! Guter Einwand. Spart vermutlich auch hier und da noch Dinge die jetzt by-Value passieren, ohne dass ich davon weiss :lol:. (Das mit dem sealed war übrigens ein 1a Tipp. Diese Auswirkung war mir nicht bewusst.) PS: Allein der Gedanke daran, für einen Pixel je eine eigene Klasseninstanz... wuahhhh! Aber wir ham's ja =) |
Re: [C#] Dies ist keine Variable?
Man mag es nicht glauben, aber in der CLR (und der Java-VM und anderen GC-Umgebungen) sind Allokationen in der Regel spottbillig. Gerade wenn du viele kleine Instanzen hast, ist jede Allokation im Prinzip nichts mehr als ein Registerinkrement. Wenn du effizient Listen umdrehen willst, kannst du dir auch einen Listenwrapper schreiben, der einfach die Zugriffe verkehrt herum auf die Basisliste abbildet. Da gibt's einiges an Möglichkeiten :)
|
Re: [C#] Dies ist keine Variable?
Du machst mich ganz schwindelig =) Ich knobel hier noch an elementarstem funktionalem Design, und du kommst mir mit Wrappern! Nein im Ernst: Jede Info die mir nachher das Leben leichter machen könnte ist ganz herzlich willkommen. Merci!
|
Re: [C#] Dies ist keine Variable?
Wegen solcher Probleme gibt es eine grundlegende Übereinkunft unter .Net-Programmierern:
![]() Aber solange die Allokationen nicht stören (messen, messen, messen ;) !), ist eine ganz normale Mutable Class natürlich auch eine Lösung :) . |
Re: [C#] Dies ist keine Variable?
Das trifft die Sache ganz prima :thumb:. Da werd ich dann doch wohl als nächstes mal meine diversen Structs wegfegen, da mir das wie ich bemerkt habe noch an anderen Stellen ganz erheblich was erleichtern könnte.
Nur zur Rückversicherung: Wenn ich eine Liste mit einem Klassentyp statt eines Structs typisiere, dann liefert mir der Zugriff darauf tatsächlich immer Referenzen, keine Kopien? |
Re: [C#] Dies ist keine Variable?
Jupp, die Identität einer Instanz, das wichtigste Merkmal von Klassen, bleibt immer bewahrt. Brechen könntest du sie höchstens von Innen heraus durch Object.MemberwiseClone (protected) oder natürlich durch Reflection.
|
Re: [C#] Dies ist keine Variable?
Prima, alles klar. Nochmals beschten Dank euch dreien!
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:48 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz