2011-01-05 7 views
68

Acabo de encontrar el tipo ArraySegment<byte> mientras se subclasifica la clase MessageEncoder.¿Cuál es el uso de la clase ArraySegment <T>?

Ahora entiendo que es un segmento de una matriz determinada, toma una compensación, no es enumerable y no tiene un indexador, pero aún no entiendo su uso. ¿Alguien puede explicar con un ejemplo?

+8

Parece que 'ArraySegment' es enumerable en .Net 4.5. – svick

+0

Por intento como [esta pregunta] (https://stackoverflow.com/questions/27965131/how-to-remove-the-first-element-in-an-array) .. –

Respuesta

19
  1. partioning Buffer para las clases IO - Utilice el mismo tampón para la utilización simultánea lectura y escritura y tienen una estructura única puede pasar alrededor de la describe toda su operación.
  2. Funciones de conjunto - Matemáticamente hablando, puede representar cualquier subconjunto contiguo utilizando esta nueva estructura . Eso significa básicamente que usted puede crear particiones de la matriz, pero no puede representar, por ejemplo, todas las probabilidades y todos los pares. Tenga en cuenta que el teaser del teléfono propuesto por The1 podría tener sido resuelto elegantemente usando particionamiento ArraySegment y una estructura de árbol . Los números finales podrían haber sido escritos al atravesar primero la profundidad del árbol. Esto tendría sido un escenario ideal en términos de memoria y velocidad de , creo.
  3. Multithreading: ahora puede generar múltiples hilos para operar sobre la misma fuente de datos mientras usa arrays segmentados como la puerta de control. Los bucles que usan cálculos discretos ahora pueden cultivarse bastante fácilmente, algo que los últimos compiladores de C++ son comenzando a hacer como un código de optimización paso.
  4. Segmentación de IU: limite las pantallas de IU mediante estructuras segmentadas . Ahora puede almacenar estructuras que representan páginas de datos que se pueden aplicar rápidamente a las funciones de visualización . Las matrices contiguas únicas se pueden usar para mostrar vistas discretas, o incluso estructuras jerárquicas como los nodos en un TreeView segmentando un almacén de datos lineales en segmentos de recopilación de nodos.

En este ejemplo, vamos a ver cómo se puede utilizar la matriz original, las propiedades de offset y count, y también cómo puede recorrer los elementos especificados en el ArraySegment.

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 es solo una estructura.Mi mejor opción es que su propósito es permitir que pase un segmento de una matriz sin tener que hacer una copia. – Brian

+1

Creo que la declaración de condición del bucle for debe ser 'i

+1

+1 por los hechos que mencionas, pero @Eren tiene razón: no puedes iterar elementos de un segmento como ese. –

9

Es un poco de estructura soldado débil que no hace más que mantener una referencia a una matriz y almacena una gama de índices. Un poco peligroso, tenga en cuenta que no hace una copia de los datos de la matriz y de ninguna manera hace que la matriz sea inmutable ni exprese la necesidad de inmutabilidad. El patrón de programación más típico es simplemente mantener o pasar la matriz y una variable o parámetro de longitud, como se hace en los métodos .NET BeginRead(), String.SubString(), Encoding.GetString(), etc., etc.

No tiene mucho uso dentro del.NET Framework, a excepción de lo que parece ser un programador de Microsoft en particular que trabajó en sockets web y WCF le gusta. Cuál es probablemente la guía adecuada, si te gusta, úsala. Hizo un peek-a-boo en .NET 4.6, el método adicional MemoryStream.TryGetBuffer() lo usa. Preferido por tener dos argumentos out, supongo.

En general, la noción más universal de sectores es una de las mejores en la lista de deseos de los ingenieros principales de .NET como Mads Torgersen y Stephen Toub. Este último inició la propuesta de sintaxis array[:] hace un tiempo, puedes ver lo que han estado pensando en this Roslyn page. Asumo que obtener soporte de CLR es en lo que esto depende en última instancia. Esto está siendo pensado activamente para C# versión 7 afaik, no pierda de vista System.Slices.

Actualización: vínculo inactivo, esto enviado en la versión 7.2 como Span.

+0

+1 No es una estructura maravillosa. :) –

+33

Si está evitando una copia costosa, entonces no es inútil ... – CRice

+0

"No es muy útil" - Lo encontré increíblemente útil en un sistema que desafortunadamente requería micro optimizaciones debido a la limitación de memoria. El hecho de que haya * tampoco * otras soluciones "típicas" no le quitan valor a su utilidad – AaronHS

34

ArraySegment<T> ha convertido en un lot more useful in .NET 4.5 ya que ahora implementa:

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

a diferencia del .NET 4 version que no implementó interfaces de ningún tipo.

La clase ahora puede participar en el maravilloso mundo de LINQ para que podamos hacer las cosas LINQ habituales como consultar los contenidos, invertir los contenidos sin afectar la matriz original, obtener el primer elemento, y así sucesivamente:

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

Aunque inexplicablemente hicieron 'GetEnumerator' privado, lo que significa que estás forzado a convertir a' IEnumerable '(una conversión de boxeo) para llamarlo. ¡Uf! –

7

¿Qué hay sobre una clase de contenedor? Solo para evitar copiar datos a los búferes temporales.

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 

Ejemplo:

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); 
} 

salida de la señal:

3 
4 

3 
4 
+0

Muy útil amigo, gracias, tenga en cuenta que puede hacer que implemente 'IEnumerable ' luego agregue IEnumerator 'IEnumerable.GetEnumerator() {return GetEnumerato r(); } ' – MaYaN

4

El ArraySegment es mucho más útil de lo que parece. ¡Prueba ejecutar la siguiente prueba unitaria y prepárate para sorprenderte!

[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("}"); 
     } 
    } 

Ves, todo lo que tiene que hacer es lanzar un ArraySegment a IList y va a hacer todas las cosas que probablemente esperaba que se puede hacer en el primer lugar. Observe que el tipo sigue siendo ArraySegment, aunque se comporte como una lista normal.

SALIDA:

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

Es una lástima que sea necesario convertirlo a' IList '. Yo esperaría que el indexador sea 'público '. – xmedeko

Cuestiones relacionadas