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.

War es hilfreich?

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.

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

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