2011-01-05 14 views
68

Ich bin gerade auf den ArraySegment<byte> Typ während Unterklassen der MessageEncoder Klasse.Was ist die Verwendung von ArraySegment <T> Klasse?

Ich verstehe jetzt, dass es ein Segment eines gegebenen Arrays ist, nimmt einen Offset, ist nicht aufzählbar und hat keinen Indexer, aber ich verstehe immer noch nicht seine Verwendung. Kann jemand bitte mit einem Beispiel erklären?

+8

Es sieht aus wie 'ArraySegment' in .Net 4.5 ist abzählbar. – svick

+0

Für Versuch wie [diese Frage] (https://stackoverflow.com/questions/27965131/how-to-remove-the-first-element-in-an-array) .. –

Antwort

19
  1. Buffer partioning für IO-Klassen - Verwenden Sie den gleichen Puffer für die gleichzeitige Lese- und Schreiboperationen und eine einzelne Struktur, die Sie um passieren kann die Ihre gesamte Vorgang beschreibt.
  2. Satzfunktionen - Mathematisch können Sie beliebige zusammenhängende Teilmengen mit dieser neuen Struktur darstellen. Das bedeutet im Grunde, dass Sie Partitionen des Arrays erstellen können, aber Sie können nicht sagen, alle Quoten und alle Evens. Beachten Sie, dass das Telefon Teaser von The1 könnte elegant gelöst mit ArraySegment Partitionierung und eine Struktur Struktur haben. Die endgültigen Zahlen konnten ausgeschrieben werden, indem zuerst die Baumtiefe durchlaufen wurde. Dies würde ein ideales Szenario in Bezug auf Speicher und Geschwindigkeit sein, glaube ich.
  3. Multithreading - Sie können jetzt mehrere Threads erstellen, um über die gleiche Datenquelle zu arbeiten, während Sie segmentierte Arrays als Control Gate verwenden. Loops , die diskrete Berechnungen verwenden können jetzt sehr einfach herausgearbeitet werden, etwas , dass die neuesten C++ - Compiler sind beginnend als Code-Optimierung zu tun Schritt.
  4. UI-Segmentierung - Beschränken Sie Ihre UI-Anzeigen mit segmentierten Strukturen. Sie können jetzt Strukturen speichern, die Seiten mit Daten darstellen, die schnell auf die Anzeigefunktionen angewendet werden können. Einzelne zusammenhängende Arrays können verwendet werden, um diskrete Ansichten oder sogar hierarchische Strukturen wie die Knoten in einem TreeView durch Segmentierung einer linearen Daten Speicher in Knoten Sammlung Segmente anzuzeigen.

In diesem Beispiel betrachten wir, wie Sie das ursprüngliche Array verwenden können, die Offset und Count Eigenschaften, und auch, wie Sie eine Schleife durch die angegebenen Elemente in der Array können.

using System; 

class Program 
{ 
    static void Main() 
    { 
     // Create an ArraySegment from this array. 
     int[] array = { 10, 20, 30 }; 
     ArraySegment<int> segment = new ArraySegment<int>(array, 1, 2); 

     // Write the array. 
     Console.WriteLine("-- Array --"); 
     int[] original = segment.Array; 
     foreach (int value in original) 
     { 
      Console.WriteLine(value); 
     } 

     // Write the offset. 
     Console.WriteLine("-- Offset --"); 
     Console.WriteLine(segment.Offset); 

     // Write the count. 
     Console.WriteLine("-- Count --"); 
     Console.WriteLine(segment.Count); 

     // Write the elements in the range specified in the ArraySegment. 
     Console.WriteLine("-- Range --"); 
     for (int i = segment.Offset; i < segment.Count+segment.Offset; i++) 
     { 
      Console.WriteLine(segment.Array[i]); 
     } 
    } 
} 

ArraySegment Structure - what were they thinking?

+3

ArraySegment ist nur eine Struktur.Meine beste Vermutung ist, dass sein Zweck darin besteht, dass ein Segment eines Arrays herumgereicht werden kann, ohne dass es kopiert werden muss. – Brian

+1

Ich glaube, dass die Bedingung Anweisung der For-Schleife sollte "i

+1

+1 für die Fakten, die Sie erwähnt haben, aber @Eren hat Recht: Sie können die Elemente eines Segments nicht so iterieren. –

9

Es ist ein mickrig struct kleiner Soldat, der nichts tut, sondern eine Referenz auf ein Array halten und speichert einen Indexbereich. Ein wenig gefährlich, seien Sie vorsichtig, dass es keine Kopie der Array-Daten erstellt und das Array in keiner Weise unveränderlich macht oder die Notwendigkeit der Unveränderbarkeit ausdrückt. Das typische Programmiermuster besteht darin, das Array und eine Längenvariable oder einen Parameter einfach beizubehalten oder zu übergeben, wie es in den .NET BeginRead() - Methoden String.SubString(), Encoding.GetString() usw. usw. der Fall ist.

Es wird nicht viel Nutzen innerhalb der.NET Framework, abgesehen von etwas, das wie ein bestimmter Microsoft-Programmierer aussieht, der an Web-Sockets gearbeitet hat, und WCF, der es mag. Welches ist wahrscheinlich die richtige Anleitung, wenn Sie es mögen, dann verwenden Sie es. Es hat in .NET 4.6 einen Peek-a-boo gemacht, die hinzugefügte MemoryStream.TryGetBuffer() Methode benutzt es. Ich bevorzuge gegenüber zwei out Argumente.

Im Allgemeinen ist der allgemeinere Begriff Scheiben auf der Wunschliste der wichtigsten .NET-Ingenieure wie Mads Torgersen und Stephen Toub hoch. Letztere haben vor einer Weile den Syntaxvorschlag array[:] gestartet, Sie können sehen, worüber sie in this Roslyn page nachgedacht haben. Ich gehe davon aus, dass es letztendlich darauf ankommt, CLR-Unterstützung zu bekommen. Dies wird aktiv für C# Version 7 afaik gedacht, behalte dein Auge auf System.Slices.

Update: toter Link, geliefert in Version 7.2 als Span.

+0

+1 Es ist keine Wunder-Struktur. :) –

+33

Wenn es eine teure Kopie vermeidet, dann ist es nicht nutzlos ... – CRice

+0

"Es ist nicht sehr nützlich" - Ich fand es unglaublich nützlich in einem System, das leider aufgrund der Speicherbegrenzung Mikro-Optimierungen benötigt sind * auch * andere "typische" Lösungen schmälern ihren Nutzen nicht – AaronHS

34

ArraySegment<T> hat sich zu einem lot more useful in .NET 4.5, wie es jetzt implementiert:

  • IList<T>
  • ICollection<T>
  • IEnumerable<T>
  • IEnumerable
  • IReadOnlyList<T>
  • IReadOnlyCollection<T>

im Gegensatz zu .NET 4 version, die keinerlei Schnittstellen implementiert.

Die Klasse ist nun in der Lage, an der wunderbaren Welt von LINQ teilzunehmen, so dass wir die üblichen LINQ-Dinge wie Abfragen des Inhalts, Rückgängigmachen des Inhalts ohne Auswirkungen auf das ursprüngliche Array, Abrufen des ersten Elements und so weiter tun können:

var array = new byte[] { 5, 8, 9, 20, 70, 44, 2, 4 }; 
array.Dump(); 
var segment = new ArraySegment<byte>(array, 2, 3); 
segment.Dump(); // output: 9, 20, 70 
segment.Reverse().Dump(); // output 70, 20, 9 
segment.Any(s => s == 99).Dump(); // output false 
segment.First().Dump(); // output 9 
array.Dump(); // no change 
+0

Obwohl sie unerklärlicherweise 'GetEnumerator' privat gemacht, was bedeutet, dass Sie gezwungen sind, zu' IEnumerable '(eine Box-Konvertierung) Ugh! –

7

Was ist mit einer Wrapper-Klasse? Nur um zu vermeiden, Daten in temporäre Puffer zu kopieren.

public class SubArray<T> { 
     private ArraySegment<T> segment; 

     public SubArray(T[] array, int offset, int count) { 
      segment = new ArraySegment<T>(array, offset, count); 
     } 
     public int Count { 
      get { return segment.Count; } 
     } 

     public T this[int index] { 
      get { 
       return segment.Array[segment.Offset + index]; 
      } 
     } 

     public T[] ToArray() { 
      T[] temp = new T[segment.Count]; 
      Array.Copy(segment.Array, segment.Offset, temp, 0, segment.Count); 
      return temp; 
     } 

     public IEnumerator<T> GetEnumerator() { 
      for (int i = segment.Offset; i < segment.Offset + segment.Count; i++) { 
       yield return segment.Array[i]; 
      } 
     } 
    } //end of the class 

Beispiel:

byte[] pp = new byte[] { 1, 2, 3, 4 }; 
SubArray<byte> sa = new SubArray<byte>(pp, 2, 2); 

Console.WriteLine(sa[0]); 
Console.WriteLine(sa[1]); 
//Console.WriteLine(b[2]); exception 

Console.WriteLine(); 
foreach (byte b in sa) { 
    Console.WriteLine(b); 
} 

Ouput:

3 
4 

3 
4 
+0

Sehr nützlicher Buddy, danke, beachten Sie, dass Sie IEnumerable implementieren können 'dann IEnumerator hinzufügen 'IEnumerable.GetEnumerator() {return GetEnumerato r(); } ' – MaYaN

4

Der Array ist viel nützlicher als Sie vielleicht denken. Probiere den folgenden Komponententest aus und bereite dich darauf vor, erstaunt zu sein!

[TestMethod] 
    public void ArraySegmentMagic() 
    { 
     var arr = new[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 

     var arrSegs = new ArraySegment<int>[3]; 
     arrSegs[0] = new ArraySegment<int>(arr, 0, 3); 
     arrSegs[1] = new ArraySegment<int>(arr, 3, 3); 
     arrSegs[2] = new ArraySegment<int>(arr, 6, 3); 
     for (var i = 0; i < 3; i++) 
     { 
      var seg = arrSegs[i] as IList<int>; 
      Console.Write(seg.GetType().Name.Substring(0, 12) + i); 
      Console.Write(" {"); 
      for (var j = 0; j < seg.Count; j++) 
      { 
       Console.Write("{0},", seg[j]); 
      } 
      Console.WriteLine("}"); 
     } 
    } 

Sie sehen, alles, was Sie tun müssen, ist eine Array zu IList gegossen und es wird all die Dinge tun Sie es wahrscheinlich in erster Linie zu tun erwartet. Beachten Sie, dass der Typ immer noch ArraySegment ist, obwohl er sich wie eine normale Liste verhält.

OUTPUT:

ArraySegment0 {0,1,2,} 
ArraySegment1 {3,4,5,} 
ArraySegment2 {6,7,8,} 
+2

Es ist schade, dass es notwendig ist, es in' IList 'zu werfen. Ich würde erwarten, dass der Indexer "öffentlich" ist. – xmedeko

Verwandte Themen