Sind unveränderliche Arrays möglich in .NET?
-
03-07-2019 - |
Frage
Ist es möglich, irgendwie ein System.Array
als unveränderlich zu markieren. Wenn hinter einem setzen öffentlich-get / Private-Set können sie nicht hinzugefügt werden, da es Neuvergabe und Neuzuweisung erfordert, sondern ein Verbraucher kann so eingestellt haupt noch tief sie wollen:
public class Immy
{
public string[] { get; private set; }
}
Ich dachte, das readonly
Stichwort den Trick tun könnte, aber kein Glück.
Lösung
ReadOnlyCollection<T>
ist wahrscheinlich das, was Sie suchen. Sie stellen keine Add()
Methode haben.
Andere Tipps
Die Framework Design Guidelines eine Kopie des Array vorschlagen zurück. Auf diese Weise können die Verbraucher nicht Elemente aus dem Array ändern.
// bad code
// could still do Path.InvalidPathChars[0] = 'A';
public sealed class Path {
public static readonly char[] InvalidPathChars =
{ '\"', '<', '>', '|' };
}
diese sind besser:
public static ReadOnlyCollection<char> GetInvalidPathChars(){
return Array.AsReadOnly(InvalidPathChars);
}
public static char[] GetInvalidPathChars(){
return (char[])InvalidPathChars.Clone();
}
Die Beispiele sind gerade aus dem Buch.
Bitte finden Sie unter
Sie könnten Array.AsReadOnly Methode verwenden, um zurückzukehren.
Ich glaube, best practice ist IList
Siehe Arrays als etwas Schädlich für weitere Informationen.
Edit:. Arrays können nicht nur gelesen werden, aber sie können auf schreibgeschützte Implementierungen IList umgewandelt werden über Array.AsReadOnly () als @shahkalpesh weist darauf hin,
.NET neigt dazu, von Arrays für alle zu steuern weg, aber die einfachste und traditionelle Anwendungsfälle. Für alles andere gibt es verschiedene enumerable / Sammlung Implementierungen.
Wenn Sie wollen als unveränderlich eine Reihe von Daten zu markieren, Sie gehen über die Fähigkeit von einem traditionellen Array zur Verfügung gestellt. .NET bietet äquivalente Fähigkeit, aber technisch nicht in der Form einer Anordnung. Um eine unveränderliche Sammlung aus einem Array zu erhalten, verwenden Array.AsReadOnly<T>
:
var mutable = new[]
{
'a', 'A',
'b', 'B',
'c', 'C',
};
var immutable = Array.AsReadOnly(mutable);
immutable
wird ein ReadOnlyCollection<char>
Instanz. System.Collections: Als allgemeiner Anwendungsfall können Sie ein ReadOnlyCollection<T>
von jedem generischen IList<T>
Implementierung
var immutable = new ReadOnlyCollection<char>(new List<char>(mutable));
Beachten Sie, dass es sich um eine generische Implementierung sein muss; plain old IList
wird nicht funktionieren, was bedeutet, dass Sie diese Methode nicht auf einem traditionellen Array verwenden können, die nur Geräte IList
. Dies bringt die Möglichkeit der Verwendung von ReadOnlyCollection<T>
werden Sie auf alle Funktionen zugreifen, die Sie von einem unveränderlichen Array erwarten:
// Note that .NET favors Count over Length; all but traditional arrays use Count:
for (var i = 0; i < immutable.Count; i++)
{
// this[] { get } is present, as ReadOnlyCollection<T> implements IList<T>:
var element = immutable[i]; // Works
// this[] { set } has to be present, as it is required by IList<T>, but it
// will throw a NotSupportedException:
immutable[i] = element; // Exception!
}
// ReadOnlyCollection<T> implements IEnumerable<T>, of course:
foreach (var character in immutable)
{
}
// LINQ works fine; idem
var lowercase =
from c in immutable
where c >= 'a' && c <= 'z'
select c;
// You can always evaluate IEnumerable<T> implementations to arrays with LINQ:
var mutableCopy = immutable.ToArray();
// mutableCopy is: new[] { 'a', 'A', 'b', 'B', 'c', 'C' }
var lowercaseArray = lowercase.ToArray();
// lowercaseArray is: new[] { 'a', 'b', 'c' }
Das einzige, was hinzuzufügen ist, dass Arrays bedeuten Wandelbarkeit. Wenn Sie ein Array aus einer Funktion zurückzugeben, Sie schlagen vor, an den Client-Programmierer, die sie kann / sollte die Dinge ändern.
Im Anschluss an Matts Antwort ist IList eine komplette abstrakte Schnittstelle zu einem Array, so ist es erlaubt hinzuzufügen, zu entfernen, etc. Ich bin nicht sicher, warum Lippert es als Alternative zu IEnumerable vorschlagen erscheint, wo Unveränderlichkeit benötigt wird. ( Edit: , da die IList-Implementierung Ausnahmen für diese mutieren Methoden werfen kann, wenn man wie diese Art der Sache).
Vielleicht trägt eine andere Sache im Auge, dass die Punkte auf der Liste auch wandelbar Zustand haben können. Wenn Sie wirklich der Anrufer nicht wollen solchen Zustand zu ändern, haben Sie einige Optionen:
Stellen Sie sicher, dass die Punkte auf der Liste unveränderlich sind (wie in Ihrem Beispiel: string ist unveränderlich).
Gibt einen tiefen Klon von allem, so dass in diesem Fall, dass Sie ein Array ohnehin nutzen könnten.
Gibt eine Schnittstelle, die Nur-Lese-Zugriff auf ein Element gibt:
interface IImmutable
{
public string ValuableCustomerData { get; }
}
class Mutable, IImmutable
{
public string ValuableCustomerData { get; set; }
}
public class Immy
{
private List<Mutable> _mutableList = new List<Mutable>();
public IEnumerable<IImmutable> ImmutableItems
{
get { return _mutableList.Cast<IMutable>(); }
}
}
Beachten Sie, dass jeder Wert erreichbar von der IImmutable Schnittstelle muss selbst unveränderlich (z string) sein, oder auch eine Kopie, die Sie on-the-fly zu machen.
Am besten Sie hoffen kann, zu tun, um eine bestehende Sammlung erweitern Sie Ihre eigenen zu bauen. Das große Problem ist, dass es als jeder bestehende Sammlung Typ anders funktionieren würde, weil jeder Anruf eine neue Kollektion zurückkehren würde.
Sie möchten vielleicht auf eine ähnliche meine Antwort überprüfen, Frage für weitere Ideen, Sammlungen auf einem Objekt ausgesetzt wird.