O Span<T> é um novo tipo de valor na plataforma .NET que permite reduzir a alocação de memória.
Este recurso permite o gerenciamento fortemente tipado da memória contígua, independentemente de como ela foi alocada. Isso facilita a manutenção do código e melhora muito o desempenho dos aplicativos, reduzindo o número de alocações e cópias de memória necessárias. E ele faz isso oferecendo acesso seguro com características de desempenho semelhantes às das matrizes.
Uma struct Span<T> representa uma região contígua de memória arbitrária, e, uma instância de Span<T> é geralmente usada para manter os elementos de uma matriz ou uma parte de uma matriz. Ao contrário de uma matriz, no entanto, uma instância de Span<T> pode apontar para memória gerenciada, memória nativa ou memória gerenciada na pilha.
Dessa forma a utilidade em usar este recurso esta em podermos simplesmente fatiar um pedaço de memória existente e gerenciá-lo, sem ter que copiá-lo e alocar uma nova memória.
Podemos usar Span com:
- arrays
- strings
- alocação de stack
- buffers nativos
A seguir temos uma lista dos tipos que podemos converter para Span<T> :
- Arrays
- Pointers
- stackalloc
- intPtr
E usando ReadOnlySpan<T> podemos converter os seguintes tipos :
- Arrays
- Pointers
- stackalloc
- intPtr
- string
Principais propriedades :
- Empty – Retorna um objeto Span<T> vazio;
- IsEmpty – Retorna um valor que indica se o Span<T> atual está vazio.
- Item[] – Obtém o elemento no índice baseado em zero especificado.
- Length – Retorna o tamanho do intervalo atual.
Principais métodos :
- Clear – Limpa o conteúdo deste objeto Span<T>;
- CopyTo – Copia o conteúdo deste Span<T> para um Span<T> de destino.
- Fill – Preenche os elementos desse intervalo com um valor especificado.
- GetEnumerator – Retorna um enumerador para este Span<T>.
- Slice(int32) – Forma uma fatia com base no intervalo atual que começa em um índice especificado.
- Slice(int32,int32) – Forma uma fatia com base no intervalo atual que começa em um índice especificado para um tamanho especificado.
- ToArray – Copia o conteúdo desse intervalo para uma nova matriz.
- ToString – Retorna a representação de cadeia de caracteres desse objeto Span<T>.
- TryCopyTo – Tenta copiar o Span<T> atual para um Span<T> de destino e retorna um valor que indica se a operação de cópia foi bem-sucedida.
Exemplos de código usando Span<T>
Na verdade Span<T> é uma estrutura de referência que contém um ponteiro para a memória e o comprimento do intervalo.
Exemplo a seguir estamos criando um array com 10 posições (0 a 9) preenchidos com o valor 0.
A seguir convertemos o array para Span<byte> e estamos usando o método Slice para fatiar um intervalo que inicia na posição 5 com tamanho 2.
Depois atribuímos valores aos índices 0 e 1 da fatia e fazemos algumas comparações:
static void Main(string[] args) { Console.WriteLine(“Tecle algo para iniciar”); Console.ReadKey(); var vetor = new byte[10]; // conversão implicita de T[] para Span<T> Span<byte> bytes = vetor; //define uma fatia do intervalo atual //atribui valores às fatias if( 42 == bytesFatiados[0]) if( 43.Equals(bytesFatiados[1])) if (vetor[5].Equals(bytesFatiados[0])) if (vetor[6].Equals(bytesFatiados[1])) // lança um IndexOutOfRangeException if(vetor[2].Equals(bytes[2])) if (45.Equals(vetor[2])) Console.ReadKey(); |
Executando o projeto teremos o resultado a seguir:
A seguir veremos um exemplo onde vamos criar um novo Span e copiar elementos de um Span para outro.
static void Main(string[] args)
{
Console.WriteLine("Tecle algo para iniciar");
Console.ReadKey();
int[] arr = { 1, 2, 3, 4, 5 };
Span<int> span = arr.AsSpan();
var destino = new Span<int>(new int[arr.Length]);
span.CopyTo(destino);
span.Clear();
Console.WriteLine("Array:");
foreach (var i in arr)
{
Console.WriteLine(i);
}
Console.WriteLine("Span:");
foreach (var i in span)
{
Console.WriteLine(i);
}
Console.WriteLine("Span de destino:");
foreach (var i in destino)
{
Console.WriteLine(i);
}
Console.ReadKey();
}
|
Neste exemplo usamos o método de extensão AsSpan() para converter um array para um Span e a seguir usamos o método CopyTo para copiar o conteúdo de um Span para outro. Depois limpamos o Span usando o método Clear() e exibimos os elementos.
Resultado:
Agora você tem que considerar que como o Span é na verdade uma struct e não herda de IEnumerable, não podemos usar LINQ contra ele. Este é um grande ponto negativo quando comparado às coleções C#.
Outro detalhe é que o Span também possui um número limitado de métodos disponíveis. É muito útil para economizar memória, mas em relação à manipulação de dados para os quais aponta, não podemos fazer muita coisa.
Pegue o projeto aqui:CShp_Span1.zip