2015-12-03 17 views
5

Ja, ich weiß, das wurde schon oft diskutiert, und ich lese alle Beiträge und Kommentare zu dieser Frage, aber kann immer noch nicht etwas zu verstehen scheinen. Eine der Optionen, die MSDN bietet, um diese Verletzung zu beheben, ist die Rückgabe einer Sammlung (oder einer Schnittstelle, die von einer Sammlung implementiert wird) beim Zugriff auf die Eigenschaft. Das Problem wird jedoch offensichtlich nicht gelöst, da die meisten Sammlungen dies nicht tun unveränderlich und kann auch geändert werden. Eine andere Möglichkeit, die ich in den Antworten und Kommentaren zu dieser Frage gesehen habe, ist, das Array mit einer ReadOnlyCollection zu kapseln und es oder eine Basisschnittstelle davon zurückzugeben (wie IReadOnlyCollection), aber ich verstehe nicht, wie dies das löst Leistungsproblem.Eigenschaften sollten Arrays nicht zurückgeben

Wenn zu einem beliebigen Zeitpunkt die Eigenschaft referenziert wird, muss Speicher für eine neue ReadOnlyCollection reserviert werden, die das Array einkapselt. Worin besteht der Unterschied (in Form von Leistungsproblemen das Array/die Sammlung nicht zu bearbeiten) als einfach a zurückzugeben Kopie des ursprünglichen Arrays?

Darüber hinaus verfügt ReadOnlyCollection nur über einen Konstruktor mit IList-Argument, daher muss das Array vor dem Erstellen mit einer Liste umschlossen werden.

Wenn ich absichtlich mit einem Array innerhalb meiner Klasse (nicht als unveränderliche Sammlung) arbeiten möchte, ist die Leistung besser, wenn ich neuen Speicher für eine ReadOnlyCollection zuweisen und mein Array damit kapseln statt eine Kopie des Arrays zurückgeben?

Bitte klären Sie dies ...

+2

Wer sagt, dass es etwas mit Leistung zu tun hat? – Jamiec

+0

Ein muss Artikel von Eric auf Arrays lesen - http://blogs.msdn.com/b/ericlippert/archive/2008/09/22/arrays-consided-somewhat-harmful.aspx – Yogi

Antwort

1

Sie haben keine Notwendigkeit zu Kopie ein Array, nur Rückkehr es als IReadOnlyCollection<T>:

public class MyClass { 
    private int[] myArray = ... 

    public IReadOnlyCollection<int> MyArray { 
     get { 
     return myArray; 
     } 
    } 
    } 
+0

Ich habe gerade fast identischen Code getestet, weil es schien etwas offensichtlich zu sein (vielleicht fehlte mir etwas). Vielleicht ist die Sorge, dass jemand gewaltsam die IReadOnlyColection auf ein Array übertragen und dann ändern wird? Ich würde mir darüber aber keine Sorgen machen, als ob jemand es möchte, er kann Reflektionen nutzen, um mit privaten Feldern direkt zu tunen ... – Gerino

+4

Das ist nicht gut, wenn der Aufrufer zurück zu 'int []' (oder nur 'IList ') und dann mutiert es. Es könnte für eine interne API in Ordnung sein, aber ich würde es nicht in einer öffentlichen API tun, wo anderer Code * davon abhängig sein könnte, dass der Inhalt nicht mutiert wird. –

+0

Wie funktioniert dieser Trick? wo in der Vererbungsstruktur int [] erbt von IReadOnlyCollection ? klar, es funktioniert, aber wie ist dieses Casting möglich? Wo ist es definiert? –

9

Wenn zu irgendeinem Zeitpunkt die Eigenschaft verwiesen wird Es muss Speicher für eine neue ReadOnlyCollection reservieren, die das Array einkapselt. Worin besteht also der Unterschied (in Bezug auf Leistungsprobleme, nicht das Bearbeiten des Arrays/der Sammlung), als einfach eine Kopie des Originals zurückzugeben l Array?

A ReadOnlyCollection<T>Wraps eine Sammlung - es spielt keine kopieren die Sammlung.

Bedenken Sie:

public class Foo 
{ 
    private readonly int[] array; // Initialized in constructor 

    public IReadOnlyList<int> Array => array.ToArray(); // Copy 
    public IReadOnlyList<int> Wrapper => new ReadOnlyCollection<int>(array); // Wrap 
} 

Stellen Sie sich Ihre Array eine Million Einträge enthält. Betrachten Sie die Menge an Arbeit, die die Array Eigenschaft zu tun hat - es muss eine Kopie aller Millionen Einträge nehmen. Betrachten Sie die Menge an Arbeit, die die Wrapper Eigenschaft zu tun hat - es muss ein Objekt erstellen, das nur eine Referenz enthält.

Außerdem, wenn Sie nicht über einen kleinen zusätzlichen Speicher-Hit ausmacht, können Sie es tun, wenn statt:

public class Foo 
{ 
    private readonly int[] array; // Initialized in constructor 
    private readonly IReadOnlyList<int> Wrapper { get; } 

    public Foo(...) 
    { 
     array = ...; 
     Wrapper = new ReadOnlyCollection<int>(array); 
    } 
} 

nun die Wrapper Eigenschaft Zugriff auf keine Zuordnung überhaupt nicht beteiligt - es funktioniert nicht egal ob alle Anrufer sehen den gleichen Wrapper, weil sie es nicht mutieren können.

Verwandte Themen