Frage

Ich habe eine Liste von Strukturen und möchte ein Element ändern.Zum Beispiel :

MyList.Add(new MyStruct("john");
MyList.Add(new MyStruct("peter");

Jetzt möchte ich ein Element ändern:

MyList[1].Name = "bob"

Allerdings erhalte ich bei jedem Versuch, dies zu tun, die folgende Fehlermeldung:

Der Rückgabewert von System.Collections.generic.List.Is [int] 'kann nicht ändern, da es sich nicht um eine Variable handelt

Wenn ich eine Liste von Klassen verwende, tritt das Problem nicht auf.

Ich denke, die Antwort hat damit zu tun, dass Strukturen ein Werttyp sind.

Wenn ich also eine Liste von Strukturen habe, sollte ich sie als behandeln schreibgeschützt?Wenn ich Elemente in einer Liste ändern muss, sollte ich dann Klassen und keine Strukturen verwenden?

War es hilfreich?

Lösung

MyList[1] = new MyStruct("bob");

Strukturen in C# sollten fast immer so konzipiert sein, dass sie unveränderlich sind (das heißt, dass sie nach ihrer Erstellung keine Möglichkeit haben, ihren internen Zustand zu ändern).

In Ihrem Fall möchten Sie die gesamte Struktur im angegebenen Array-Index ersetzen und nicht versuchen, nur eine einzelne Eigenschaft oder ein einzelnes Feld zu ändern.

Andere Tipps

Nicht ganz.Das Entwerfen eines Typs als Klasse oder Struktur sollte nicht von der Notwendigkeit bestimmt werden, ihn in Sammlungen zu speichern :) Sie sollten sich die erforderliche „Semantik“ ansehen

Das Problem, das Sie sehen, ist auf die Semantik des Werttyps zurückzuführen.Jede Werttypvariable/-referenz ist eine neue Instanz.Wenn du sagst

Struct obItem = MyList[1];

Was passiert, ist, dass eine neue Instanz der Struktur erstellt wird und alle Mitglieder einzeln kopiert werden.Damit Sie einen Klon von MyList[1] haben, d.h.2 Instanzen.Wenn Sie nun obItem ändern, hat dies keine Auswirkungen auf das Original.

obItem.Name = "Gishu";  // MyList[1].Name still remains "peter"

Jetzt haben Sie 2 Minuten Geduld mit mir (es dauert eine Weile, bis ich es hinuntergeschluckt habe.)Es war für mich :) Wenn Sie wirklich Strukturen in einer Sammlung gespeichert und wie in Ihrer Frage angegeben werden, müssen Sie Ihre Struktur eine Schnittstelle freilegen (Dies führt jedoch zum Boxen).Anschließend können Sie die eigentliche Struktur über eine Schnittstellenreferenz ändern, die auf das Boxed-Objekt verweist.

Der folgende Codeausschnitt veranschaulicht, was ich gerade oben gesagt habe

public interface IMyStructModifier
{
    String Name { set; }
}
public struct MyStruct : IMyStructModifier ...

List<Object> obList = new List<object>();
obList.Add(new MyStruct("ABC"));
obList.Add(new MyStruct("DEF"));

MyStruct temp = (MyStruct)obList[1];
temp.Name = "Gishu";
foreach (MyStruct s in obList) // => "ABC", "DEF"
{
    Console.WriteLine(s.Name);
}

IMyStructModifier temp2 = obList[1] as IMyStructModifier;
temp2.Name = "Now Gishu";
foreach (MyStruct s in obList) // => "ABC", "Now Gishu"
{
    Console.WriteLine(s.Name);
}

HTH.Gute Frage.
Aktualisieren: @Hath – du hast mich laufen lassen, um zu überprüfen, ob ich etwas so Einfaches übersehen habe.(Es wäre inkonsistent, wenn Setter-Eigenschaften und Methoden dies nicht tun würden – das .Net-Universum ist immer noch ausgewogen :)
Die Setter-Methode funktioniert nicht
obList2[1] gibt eine Kopie zurück, deren Status geändert werden würde.Die ursprüngliche Struktur in der Liste bleibt unverändert.Set-via-Interface scheint also die einzige Möglichkeit zu sein.

List<MyStruct> obList2 = new List<MyStruct>();
obList2.Add(new MyStruct("ABC"));
obList2.Add(new MyStruct("DEF"));
obList2[1].SetName("WTH");
foreach (MyStruct s in obList2) // => "ABC", "DEF"
{
    Console.WriteLine(s.Name);
}

Es geht nicht so sehr darum, dass Strukturen „unveränderlich“ sind.

Das eigentliche zugrunde liegende Problem besteht darin, dass Strukturen ein Werttyp und kein Referenztyp sind.Wenn Sie also einen „Verweis“ auf die Struktur aus der Liste ziehen, wird eine neue Kopie der gesamten Struktur erstellt.Alle Änderungen, die Sie daran vornehmen, verändern also die Kopie und nicht die Originalversion in der Liste.

Wie Andrew feststellt, müssen Sie die gesamte Struktur ersetzen.An diesem Punkt denke ich jedoch, dass Sie sich fragen müssen, warum Sie überhaupt eine Struktur (anstelle einer Klasse) verwenden.Stellen Sie sicher, dass Sie dies nicht aus Gründen vorzeitiger Optimierungsbedenken tun.

An Strukturen, die über exponierte Felder verfügen oder Mutationen über Eigenschaftssetzer zulassen, ist nichts auszusetzen.Strukturen, die sich als Reaktion auf Methoden oder Property-Getter selbst verändern, sind jedoch gefährlich, da das System den Aufruf von Methoden oder Property-Gettern für temporäre Strukturinstanzen zulässt;Wenn die Methoden oder Getter Änderungen an der Struktur vornehmen, werden diese Änderungen letztendlich verworfen.

Leider sind die in .net integrierten Sammlungen, wie Sie bemerken, sehr schwach darin, darin enthaltene Werttypobjekte offenzulegen.Normalerweise ist es am besten, so etwas zu tun:

  MyStruct temp = myList[1];
  temp.Name = "Albert";
  myList[1] = temp;

Etwas nervig und überhaupt nicht threadsicher.Immer noch eine Verbesserung gegenüber einer Liste eines Klassentyps, bei der für das Gleiche möglicherweise Folgendes erforderlich ist:

  myList[1].Name = "Albert";

aber es könnte auch Folgendes erfordern:

  myList[1] = myList[1].Withname("Albert");

oder vielleicht

  myClass temp = (myClass)myList[1].Clone();
  temp.Name = "Albert";
  myList[1] = temp;

oder vielleicht eine andere Variante.Man könnte es wirklich nicht wissen, wenn man nicht sowohl myClass als auch den anderen Code untersucht hätte, der die Dinge in die Liste einfügt.Es ist durchaus möglich, dass man nicht wissen kann, ob die erste Form sicher ist, ohne den Code in Assemblys zu untersuchen, auf die man keinen Zugriff hat.Wenn dagegen „Name“ ein verfügbar gemachtes Feld von „MyStruct“ ist, funktioniert die Methode, die ich für die Aktualisierung angegeben habe, unabhängig davon, was „MyStruct“ sonst noch enthält, oder unabhängig davon, was andere Dinge möglicherweise mit „myList“ gemacht haben, bevor der Code ausgeführt wird, oder was sie möglicherweise erwarten mach danach damit.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top