No C#, o Span<T> é uma ferramenta poderosa para manipular dados de forma eficiente, sem criar cópias desnecessárias na memória. Ele permite acessar partes de arrays e strings sem precisar alocar novos objetos, tornando o código mais rápido e econômico em termos de memória.
Se você já trabalhou com manipulação de strings ou grandes quantidades de dados, provavelmente já usou arrays ou substrings para lidar com essas informações. O problema é que esses métodos tradicionais podem ser ineficientes.
Vamos entender por que o Span<T> é melhor, comparando-o com abordagens menos performáticas.
Exemplo 1: Usando Substring (Ineficiente)
Quando usamos Substring, o C# cria uma nova string na memória, o que pode gerar consumo desnecessário de recursos.
string texto = "Aprender C# é muito divertido!";
// Pegando parte da string com Substring
string parte = texto.Substring(9, 2); // Cria uma nova string "C#"
Console.WriteLine(parte); // Saída: C#
📌 Problema:
O método Substring copia os caracteres desejados para uma nova string no heap, o que significa mais uso de memória e mais trabalho para o Garbage Collector.
Exemplo 2: Usando Span<T> (Mais Eficiente)
Com Span<char>, não há cópia de dados. Em vez disso, apenas referenciamos a parte desejada da string original.
ReadOnlySpan<char> texto = "Aprender C# é muito divertido!".AsSpan();
// Pegando parte da string sem criar uma nova
ReadOnlySpan<char> parte = texto.Slice(9, 2); // Referencia "C#"
Console.WriteLine(parte.ToString()); // Saída: C#
📌 Vantagem:
✔ O Slice apenas aponta para os dados existentes. Nenhuma nova string é criada, reduzindo o uso de memória e tornando a operação mais rápida.
Exemplo 3: Manipulando um Array Sem Span<T> (Menos Performático)
Agora, vamos considerar um cenário onde precisamos somar uma parte de um array. O jeito tradicional seria criar um novo array para armazenar os valores que queremos manipular.
int[] numeros = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// Criando um novo array apenas com os números do índice 2 ao 6
int[] fatia = numeros.Skip(2).Take(5).ToArray();
// Somando os valores da fatia
int soma = fatia.Sum();
Console.WriteLine($"Soma da fatia: {soma}"); // Saída: 20
📌 Problema:
Esse código cria um novo array na memória (ToArray()), o que é desnecessário e custa mais tempo e memória.
Exemplo 4: Manipulando um Array Com Span<T> (Mais Performático)
Agora, vamos fazer a mesma operação, mas usando Span<int>.
int[] numeros = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// Criando uma fatia do array sem copiar dados
Span<int> fatia = new Span<int>(numeros, 2, 5);
// Somando os valores da fatia
int soma = 0;
foreach (var numero in fatia)
{
soma += numero;
}
Console.WriteLine($"Soma da fatia: {soma}"); // Saída: 20
📌 Vantagem:
✔ Nenhum novo array foi criado. O Span<int> apenas referencia os números existentes.
✔ O desempenho melhora porque não há cópia e não há alocação extra no heap.
Quando Usar Span<T>?
✅ Evitar cópias desnecessárias – Ao trabalhar com fatias de strings ou arrays, Span<T> melhora o desempenho sem alocar novos objetos.
✅ Processamento de grandes volumes de dados – Em buffers, manipulação de arquivos ou strings grandes, Span<T> ajuda a manter a memória sob controle.
✅ Otimização de desempenho – Reduz a carga no Garbage Collector, tornando o código mais rápido.
📌 Dica: Se você não precisa modificar os dados, use ReadOnlySpan<T> para garantir que as informações não sejam alteradas acidentalmente.
Resumo
Abordagem | O que faz? | Problema | Alternativa Melhor |
Substring() | Cria uma nova string | Usa mais memória | Span<char> |
ToArray() + Skip().Take() | Cria um novo array | Aloca no heap | Span<T>.Slice() |
List<T> | Armazena dados no heap | Requer Garbage Collector | Span<T> com stackalloc |
Agora que você já sabe como o Span<T> melhora a performance, que tal aplicá-lo no seu código para otimizar suas operações? 🚀