C# Span (Comment cela fonctionne pour les développeurs)
Span est un type introduit dans C# 7.2 comme partie de la structure Span dans l'espace de noms System. Il est conçu pour représenter une région contiguë de mémoire arbitraire. Contrairement aux tableaux ou collections telles que le tas géré, Span ne possède pas la mémoire de la pile ou la région de mémoire à laquelle il pointe ; au lieu de cela, il fournit une vue légère sur des blocs de mémoire existants. Cette caractéristique rend Span particulièrement puissant dans les scénarios où vous devez travailler efficacement avec des tampons mémoire sans entraîner de surcoût supplémentaire et de situations de code non sécurisé. Plus tard dans cet article, nous verrons également l'introduction à la bibliothèque IronPDF d'Iron Software.
Caractéristiques clés de Span
1. Gestion de la mémoire
Span en C# permet aux développeurs de travailler directement avec la mémoire sans recourir à des allocations traditionnelles sur le tas. Il offre un moyen de créer des tranches de mémoire à partir de tableaux existants ou d'autres sources de mémoire, éliminant ainsi le besoin de copies de mémoire supplémentaires.
2. Abstractions sans copie
L'une des caractéristiques remarquables de C# Span est ses abstractions sans copie. Au lieu de dupliquer les données, Span fournit un moyen de référencer efficacement la mémoire existante. Ceci est particulièrement bénéfique dans les scénarios où copier de grandes quantités de données serait irréalisable ou trop coûteux.
3. Opérations similaires aux pointeurs
Bien que C# ait traditionnellement été un langage de haut niveau et sécurisé, Span introduit un certain degré de manipulation de mémoire bas niveau, semblable au travail avec des pointeurs dans des langages comme C ou C++. Les développeurs peuvent effectuer des opérations similaires aux pointeurs sans compromettre la sécurité et la nature gérée de C#.
4. Nature immuable
Malgré ses capacités d'accès à la mémoire bas niveau, C# Span reste immuable. Cela signifie que, bien qu'il permette la manipulation de la mémoire, il impose la sécurité en empêchant les modifications non désirées.
Exemple
using System;
class Program
{
static void Main()
{
int[] array = { 1, 2, 3, 4, 5 };
// Create a span that points to the entire array
Span<int> span = array;
// Modify the data using the span
span[2] = 10;
// Print the modified array
foreach (var item in array)
{
Console.WriteLine(item);
}
}
}
using System;
class Program
{
static void Main()
{
int[] array = { 1, 2, 3, 4, 5 };
// Create a span that points to the entire array
Span<int> span = array;
// Modify the data using the span
span[2] = 10;
// Print the modified array
foreach (var item in array)
{
Console.WriteLine(item);
}
}
}
Imports System
Friend Class Program
Shared Sub Main()
Dim array() As Integer = { 1, 2, 3, 4, 5 }
' Create a span that points to the entire array
Dim span As Span(Of Integer) = array
' Modify the data using the span
span(2) = 10
' Print the modified array
For Each item In array
Console.WriteLine(item)
Next item
End Sub
End Class
ReadOnlySpan
Bien que Span
Voici quelques points clés.
1. Vue en lecture seule
Comme son nom l'indique, ReadOnlySpan
2. Représentation de la mémoire
Tout comme Span
3. Avantages de performance
Tout comme Span
4. Pas de vérification des limites
Comme avec Span
5. Utilisation avec les tranches de tableau
ReadOnlySpan
Exemple
using System;
class Program
{
static void Main()
{
int[] array = { 1, 2, 3, 4, 5 };
// Create a read-only span that points to the entire array
ReadOnlySpan<int> readOnlySpan = array;
// Access and print the data through the read-only span
foreach (var item in readOnlySpan)
{
Console.WriteLine(item);
}
// Note: The following line would result in a compilation error since readOnlySpan is read-only.
// readOnlySpan[2] = 10;
}
}
using System;
class Program
{
static void Main()
{
int[] array = { 1, 2, 3, 4, 5 };
// Create a read-only span that points to the entire array
ReadOnlySpan<int> readOnlySpan = array;
// Access and print the data through the read-only span
foreach (var item in readOnlySpan)
{
Console.WriteLine(item);
}
// Note: The following line would result in a compilation error since readOnlySpan is read-only.
// readOnlySpan[2] = 10;
}
}
Imports System
Friend Class Program
Shared Sub Main()
Dim array() As Integer = { 1, 2, 3, 4, 5 }
' Create a read-only span that points to the entire array
Dim readOnlySpan As ReadOnlySpan(Of Integer) = array
' Access and print the data through the read-only span
For Each item In readOnlySpan
Console.WriteLine(item)
Next item
' Note: The following line would result in a compilation error since readOnlySpan is read-only.
' readOnlySpan[2] = 10;
End Sub
End Class
Il existe de nombreuses façons différentes de créer ReadOnlySpan et de travailler avec. Voici quelques exemples.
1. Créer ReadOnlySpan à partir d'une chaîne
string msg = "Hello, World!";
ReadOnlySpan<char> span1 = msg.AsSpan();
// Read-only manipulation
char firstChar = span1[0];
Console.WriteLine(firstChar); // Outputs: H
string msg = "Hello, World!";
ReadOnlySpan<char> span1 = msg.AsSpan();
// Read-only manipulation
char firstChar = span1[0];
Console.WriteLine(firstChar); // Outputs: H
Dim msg As String = "Hello, World!"
Dim span1 As ReadOnlySpan(Of Char) = msg.AsSpan()
' Read-only manipulation
Dim firstChar As Char = span1(0)
Console.WriteLine(firstChar) ' Outputs: H
2. Travailler avec des sous-chaînes
Utilisez Slice sur le ReadOnlySpan
// Example usage of Slice method on ReadOnlySpan<char>
ReadOnlySpan<char> spanFromString = "Sample String".AsSpan();
ReadOnlySpan<char> substringSpan = spanFromString.Slice(7, 6); // Extracts 'String'
// Example usage of Slice method on ReadOnlySpan<char>
ReadOnlySpan<char> spanFromString = "Sample String".AsSpan();
ReadOnlySpan<char> substringSpan = spanFromString.Slice(7, 6); // Extracts 'String'
' Example usage of Slice method on ReadOnlySpan<char>
Dim spanFromString As ReadOnlySpan(Of Char) = "Sample String".AsSpan()
Dim substringSpan As ReadOnlySpan(Of Char) = spanFromString.Slice(7, 6) ' Extracts 'String'
3. Passer une sous-chaîne à une méthode
Passez ReadOnlySpan
void ProcessSubstringfromReadOnlySpan(ReadOnlySpan<char> substring)
{
// Perform operations on the substring
}
// Usage
ReadOnlySpan<char> spanFromString = "Sample String".AsSpan();
ProcessSubstringfromReadOnlySpan(spanFromString.Slice(7, 6));
void ProcessSubstringfromReadOnlySpan(ReadOnlySpan<char> substring)
{
// Perform operations on the substring
}
// Usage
ReadOnlySpan<char> spanFromString = "Sample String".AsSpan();
ProcessSubstringfromReadOnlySpan(spanFromString.Slice(7, 6));
Private Sub ProcessSubstringfromReadOnlySpan(ByVal substring As ReadOnlySpan(Of Char))
' Perform operations on the substring
End Sub
' Usage
Private spanFromString As ReadOnlySpan(Of Char) = "Sample String".AsSpan()
ProcessSubstringfromReadOnlySpan(spanFromString.Slice(7, 6))
4. Recherche dans une chaîne
ReadOnlySpanIndexOf().
ReadOnlySpan<char> stringSpan = "Hello, World!".AsSpan();
int index = stringSpan.IndexOf('W');
Console.WriteLine(index); // Outputs: 7
ReadOnlySpan<char> stringSpan = "Hello, World!".AsSpan();
int index = stringSpan.IndexOf('W');
Console.WriteLine(index); // Outputs: 7
Dim stringSpan As ReadOnlySpan(Of Char) = "Hello, World!".AsSpan()
Dim index As Integer = stringSpan.IndexOf("W"c)
Console.WriteLine(index) ' Outputs: 7
5. Utilisation des fichiers mappés en mémoire
ReadOnlySpan
using System;
using System.IO.MemoryMappedFiles;
class Program
{
static void ProcessData(ReadOnlySpan<byte> data)
{
// Process data directly from the memory-mapped file
}
static void Main()
{
using (var memmf = MemoryMappedFile.CreateFromFile("data.bin"))
{
using (var accessor = memmf.CreateViewAccessor())
{
byte[] buffer = new byte[accessor.Capacity];
accessor.ReadArray(0, buffer, 0, buffer.Length);
ReadOnlySpan<byte> dataSpan = new ReadOnlySpan<byte>(buffer);
ProcessData(dataSpan);
}
}
}
}
using System;
using System.IO.MemoryMappedFiles;
class Program
{
static void ProcessData(ReadOnlySpan<byte> data)
{
// Process data directly from the memory-mapped file
}
static void Main()
{
using (var memmf = MemoryMappedFile.CreateFromFile("data.bin"))
{
using (var accessor = memmf.CreateViewAccessor())
{
byte[] buffer = new byte[accessor.Capacity];
accessor.ReadArray(0, buffer, 0, buffer.Length);
ReadOnlySpan<byte> dataSpan = new ReadOnlySpan<byte>(buffer);
ProcessData(dataSpan);
}
}
}
}
Imports System
Imports System.IO.MemoryMappedFiles
Friend Class Program
Private Shared Sub ProcessData(ByVal data As ReadOnlySpan(Of Byte))
' Process data directly from the memory-mapped file
End Sub
Shared Sub Main()
Using memmf = MemoryMappedFile.CreateFromFile("data.bin")
Using accessor = memmf.CreateViewAccessor()
Dim buffer(accessor.Capacity - 1) As Byte
accessor.ReadArray(0, buffer, 0, buffer.Length)
Dim dataSpan As New ReadOnlySpan(Of Byte)(buffer)
ProcessData(dataSpan)
End Using
End Using
End Sub
End Class
6. Manipulation de chaînes efficace
ReadOnlySpan
Span<char> newSpan = new char[6];
ReadOnlySpan<char> spanFromString = "Sample String".AsSpan().Slice(7, 6);
spanFromString.CopyTo(newSpan);
Console.WriteLine(new string(newSpan)); // Outputs: String
Span<char> newSpan = new char[6];
ReadOnlySpan<char> spanFromString = "Sample String".AsSpan().Slice(7, 6);
spanFromString.CopyTo(newSpan);
Console.WriteLine(new string(newSpan)); // Outputs: String
Dim newSpan As Span(Of Char) = New Char(5){}
Dim spanFromString As ReadOnlySpan(Of Char) = "Sample String".AsSpan().Slice(7, 6)
spanFromString.CopyTo(newSpan)
Console.WriteLine(New String(newSpan)) ' Outputs: String
7. Passer une sous-chaîne aux API
Lors de l'utilisation de bibliothèques externes ou d'API qui fonctionnent sur des étendues de caractères.
void ExternalApiMethod(ReadOnlySpan<char> data)
{
// Call the external API with the character span
}
// Usage
ReadOnlySpan<char> spanFromString = "Sample String".AsSpan();
ExternalApiMethod(spanFromString.Slice(7, 6));
void ExternalApiMethod(ReadOnlySpan<char> data)
{
// Call the external API with the character span
}
// Usage
ReadOnlySpan<char> spanFromString = "Sample String".AsSpan();
ExternalApiMethod(spanFromString.Slice(7, 6));
Private Sub ExternalApiMethod(ByVal data As ReadOnlySpan(Of Char))
' Call the external API with the character span
End Sub
' Usage
Private spanFromString As ReadOnlySpan(Of Char) = "Sample String".AsSpan()
ExternalApiMethod(spanFromString.Slice(7, 6))
ReadOnlySpan
Limites de Span
Bien que Span en C# soit une fonctionnalité puissante avec de nombreux avantages, il vient avec certaines limitations et considérations, notamment dans le contexte de la mémoire contiguë et non contiguë. Explorons ces limitations :
1. Tampons de mémoire contiguë
1.1 Pas de gestion automatique de la mémoire
Span ne gère pas la mémoire à laquelle il pointe. Cela signifie que si la mémoire managée sous-jacente est libérée ou périme, utiliser le Span
1.2 Pas de collecte des déchets
Étant donné que Span
1.3 Vérification des limites désactivée
Span
1.4 Pas de support pour la mémoire non contiguë
Span
1.5 Toutes les opérations ne sont pas supportées
Bien que Span
1.6 Compatibilité limitée avec les plateformes
Bien que Span
2. Tampons de mémoire non contiguës
2.1 Support limité pour la mémoire non contiguë
ReadOnlySpan
2.2 Limitations structurelles
Certaines structures de données ou scénarios qui s'appuient sur la mémoire non contiguë peuvent ne pas bien s'aligner avec ReadOnlySpan
2.3 Opérations complexes sur les pointeurs
Dans les situations impliquant de la mémoire non contiguë, notamment celles nécessitant une arithmétique de pointeur complexe, ReadOnlySpan
2.4 Absence de support direct dans certaines API
Tout comme pour la mémoire contiguë, il est important de noter que toutes les API ou bibliothèques ne peuvent pas directement prendre en charge la mémoire non contiguë représentée par ReadOnlySpan
Span et mémoire non gérée
En C#, Span peut être utilisé efficacement avec de la mémoire non gérée pour effectuer des opérations liées à la mémoire de manière contrôlée et efficace. La mémoire non gérée fait référence à la mémoire qui n'est pas gérée par le collecteur de déchets du runtime .NET, et elle implique souvent l'utilisation d'allocations de mémoire native et de désallocations. Voici comment Span peut être utilisé avec de la mémoire non gérée en C#.
Allouer de la mémoire non gérée
Pour allouer de la mémoire non gérée, vous pouvez utiliser la classe System.Runtime.InteropServices.MemoryMarshal. La méthode Marshal.AllocHGlobal alloue de la mémoire et renvoie un pointeur vers le bloc alloué. La mémoire allouée ou l'adresse mémoire est conservée dans un pointeur unmanagedMemory et aura un accès en lecture-écriture. Les régions contiguës de mémoire peuvent être facilement accessibles.
using System;
using System.Runtime.InteropServices;
class Program
{
static void Main()
{
const int bufferSize = 100;
IntPtr unmanagedMemory = Marshal.AllocHGlobal(bufferSize);
// Create a Span from the unmanaged memory
Span<byte> span = new Span<byte>(unmanagedMemory.ToPointer(), bufferSize);
// Use the Span as needed...
// Don't forget to free the unmanaged memory when done
Marshal.FreeHGlobal(unmanagedMemory);
}
}
using System;
using System.Runtime.InteropServices;
class Program
{
static void Main()
{
const int bufferSize = 100;
IntPtr unmanagedMemory = Marshal.AllocHGlobal(bufferSize);
// Create a Span from the unmanaged memory
Span<byte> span = new Span<byte>(unmanagedMemory.ToPointer(), bufferSize);
// Use the Span as needed...
// Don't forget to free the unmanaged memory when done
Marshal.FreeHGlobal(unmanagedMemory);
}
}
Imports System
Imports System.Runtime.InteropServices
Friend Class Program
Shared Sub Main()
Const bufferSize As Integer = 100
Dim unmanagedMemory As IntPtr = Marshal.AllocHGlobal(bufferSize)
' Create a Span from the unmanaged memory
Dim span As New Span(Of Byte)(unmanagedMemory.ToPointer(), bufferSize)
' Use the Span as needed...
' Don't forget to free the unmanaged memory when done
Marshal.FreeHGlobal(unmanagedMemory)
End Sub
End Class
Dans le code source ci-dessus, nous allouons un bloc de mémoire non gérée en utilisant Marshal.AllocHGlobal puis créons un Span<byte> en utilisant le pointeur obtenu à partir de la mémoire non gérée. Cela nous permet de travailler avec de la mémoire non gérée en utilisant l'API familière de Span. Il est important de noter que lorsque vous travaillez avec de la mémoire non gérée, vous êtes responsable de gérer l'allocation et la désallocation de la mémoire.
Copier des données vers et depuis la mémoire non gérée
Span fournit des méthodes comme Slice, CopyTo et ToArray qui peuvent être utilisées pour copier efficacement des données entre la mémoire gérée et la mémoire non gérée.
using System;
using System.Runtime.InteropServices;
class Program
{
static void Main()
{
// Managed array to copy data from
int[] sourceArray = { 1, 2, 3, 4, 5 };
// Allocate unmanaged memory for the destination data
IntPtr destinationPointer = Marshal.AllocHGlobal(sourceArray.Length * sizeof(int));
try
{
// Create a Span<int> from the source array
Span<int> sourceSpan = sourceArray;
// Create a Span<int> from the allocated unmanaged memory
Span<int> destinationSpan = new Span<int>(destinationPointer.ToPointer(), sourceArray.Length);
// Copy data from the source Span<int> to the destination Span<int>
sourceSpan.CopyTo(destinationSpan);
// Print the values in the destination memory
Console.WriteLine("Values in the destination memory:");
foreach (var value in destinationSpan)
{
Console.Write($"{value} ");
}
}
finally
{
// Deallocate the unmanaged memory when done
Marshal.FreeHGlobal(destinationPointer);
}
}
}
using System;
using System.Runtime.InteropServices;
class Program
{
static void Main()
{
// Managed array to copy data from
int[] sourceArray = { 1, 2, 3, 4, 5 };
// Allocate unmanaged memory for the destination data
IntPtr destinationPointer = Marshal.AllocHGlobal(sourceArray.Length * sizeof(int));
try
{
// Create a Span<int> from the source array
Span<int> sourceSpan = sourceArray;
// Create a Span<int> from the allocated unmanaged memory
Span<int> destinationSpan = new Span<int>(destinationPointer.ToPointer(), sourceArray.Length);
// Copy data from the source Span<int> to the destination Span<int>
sourceSpan.CopyTo(destinationSpan);
// Print the values in the destination memory
Console.WriteLine("Values in the destination memory:");
foreach (var value in destinationSpan)
{
Console.Write($"{value} ");
}
}
finally
{
// Deallocate the unmanaged memory when done
Marshal.FreeHGlobal(destinationPointer);
}
}
}
Imports System
Imports System.Runtime.InteropServices
Friend Class Program
Shared Sub Main()
' Managed array to copy data from
Dim sourceArray() As Integer = { 1, 2, 3, 4, 5 }
' Allocate unmanaged memory for the destination data
Dim destinationPointer As IntPtr = Marshal.AllocHGlobal(sourceArray.Length * Len(New Integer()))
Try
' Create a Span<int> from the source array
Dim sourceSpan As Span(Of Integer) = sourceArray
' Create a Span<int> from the allocated unmanaged memory
Dim destinationSpan As New Span(Of Integer)(destinationPointer.ToPointer(), sourceArray.Length)
' Copy data from the source Span<int> to the destination Span<int>
sourceSpan.CopyTo(destinationSpan)
' Print the values in the destination memory
Console.WriteLine("Values in the destination memory:")
For Each value In destinationSpan
Console.Write($"{value} ")
Next value
Finally
' Deallocate the unmanaged memory when done
Marshal.FreeHGlobal(destinationPointer)
End Try
End Sub
End Class
Dans cet exemple :
Marshal.AllocHGlobalalloue de la mémoire non gérée pour les données de destination.new Span<int>(destinationPointer.ToPointer(), sourceArray.Length)crée unSpan<int>à partir de la mémoire non gérée allouée.- La méthode
sourceSpan.CopyTo(destinationSpan)copie les données du tableau géré vers la mémoire non gérée. - Les valeurs dans la mémoire de destination sont imprimées pour vérifier l'opération de copie.
- La méthode
Marshal.FreeHGlobal(destinationPointer)est utilisée pour libérer la mémoire non gérée une fois terminée.
Utiliser du code non sécurisé
Lorsque vous traitez de la mémoire non gérée, vous pouvez également utiliser du code non sécurisé avec des pointeurs. Dans de tels cas, vous pouvez obtenir un pointeur à partir de Span en utilisant la méthode Unsafe.AsPointer().
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
class Program
{
static void Main()
{
const int bufferSize = 100;
IntPtr unmanagedMemory = Marshal.AllocHGlobal(bufferSize);
// Create a Span from the unmanaged memory
Span<byte> span = new Span<byte>(unmanagedMemory.ToPointer(), bufferSize);
// Use unsafe code to work with pointers
unsafe
{
byte* pointer = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(span));
// Use the pointer as needed...
}
// Don't forget to free the unmanaged memory when done
Marshal.FreeHGlobal(unmanagedMemory);
}
}
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
class Program
{
static void Main()
{
const int bufferSize = 100;
IntPtr unmanagedMemory = Marshal.AllocHGlobal(bufferSize);
// Create a Span from the unmanaged memory
Span<byte> span = new Span<byte>(unmanagedMemory.ToPointer(), bufferSize);
// Use unsafe code to work with pointers
unsafe
{
byte* pointer = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(span));
// Use the pointer as needed...
}
// Don't forget to free the unmanaged memory when done
Marshal.FreeHGlobal(unmanagedMemory);
}
}
Imports System
Imports System.Runtime.InteropServices
Imports System.Runtime.CompilerServices
Friend Class Program
Shared Sub Main()
Const bufferSize As Integer = 100
Dim unmanagedMemory As IntPtr = Marshal.AllocHGlobal(bufferSize)
' Create a Span from the unmanaged memory
Dim span As New Span(Of Byte)(unmanagedMemory.ToPointer(), bufferSize)
' Use unsafe code to work with pointers
'INSTANT VB TODO TASK: C# 'unsafe' code is not converted by Instant VB:
' unsafe
' {
' byte* pointer = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(span));
' ' Use the pointer as needed...
' }
' Don't forget to free the unmanaged memory when done
Marshal.FreeHGlobal(unmanagedMemory)
End Sub
End Class
Dans cet exemple, nous utilisons la méthode Unsafe.AsPointer pour obtenir un pointeur à partir de Span. Cela nous permet d'utiliser du code non sécurisé lorsque nous travaillons directement avec des pointeurs.
Rappelez-vous, quand vous travaillez avec de la mémoire non gérée, il est crucial de gérer correctement l'allocation et la désallocation pour éviter les fuites de mémoire. Libérez toujours la mémoire non gérée en utilisant des méthodes appropriées, telles que Marshal.FreeHGlobal(). De plus, faites preuve de prudence lorsque vous utilisez du code non sécurisé, car cela peut introduire des risques de sécurité potentiels si ce n'est pas manipulé correctement.
Span et appels de méthode asynchrones
Utiliser Span en conjonction avec des appels de méthode asynchrones en C# est une combinaison puissante, notamment lors du traitement de grandes quantités de données ou d'opérations d'E/S. Le but est de gérer efficacement les opérations asynchrones sans copie de données inutiles. Voyons comment tirer parti de Span dans des scénarios asynchrones :
1. Opérations d'E/S asynchrones :
Lors de la gestion d'opérations I/O asynchrones, telles que la lecture ou l'écriture de données dans un flux, vous pouvez utiliser Memory
using System;
using System.IO;
using System.Threading.Tasks;
class Program
{
static async Task ProcessDataAsync(Stream stream)
{
const int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
while (true)
{
int bytesRead = await stream.ReadAsync(buffer.AsMemory());
if (bytesRead == 0)
break;
// Process the data using Span without unnecessary copying
ProcessData(buffer.AsSpan(0, bytesRead));
}
}
static void ProcessData(Span<byte> data)
{
// Perform operations on the data
}
}
using System;
using System.IO;
using System.Threading.Tasks;
class Program
{
static async Task ProcessDataAsync(Stream stream)
{
const int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
while (true)
{
int bytesRead = await stream.ReadAsync(buffer.AsMemory());
if (bytesRead == 0)
break;
// Process the data using Span without unnecessary copying
ProcessData(buffer.AsSpan(0, bytesRead));
}
}
static void ProcessData(Span<byte> data)
{
// Perform operations on the data
}
}
Imports System
Imports System.IO
Imports System.Threading.Tasks
Friend Class Program
Private Shared Async Function ProcessDataAsync(ByVal stream As Stream) As Task
Const bufferSize As Integer = 4096
Dim buffer(bufferSize - 1) As Byte
Do
Dim bytesRead As Integer = Await stream.ReadAsync(buffer.AsMemory())
If bytesRead = 0 Then
Exit Do
End If
' Process the data using Span without unnecessary copying
ProcessData(buffer.AsSpan(0, bytesRead))
Loop
End Function
Private Shared Sub ProcessData(ByVal data As Span(Of Byte))
' Perform operations on the data
End Sub
End Class
Dans cet exemple, la méthode ReadAsync lit des données d'un flux dans le tampon de manière asynchrone. La méthode ProcessData traite ensuite les données directement à partir de Span
2. Opérations de fichiers asynchrones :
De la même manière que les opérations d'E/S, lors de la manipulation d'opérations de fichiers asynchrones, vous pouvez utiliser Span pour traiter efficacement les données sans copie supplémentaire.
using System;
using System.IO;
using System.Threading.Tasks;
class Program
{
static async Task ProcessFileAsync(string filePath)
{
const int bufferSize = 4096;
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[bufferSize];
while (true)
{
int bytesRead = await fileStream.ReadAsync(buffer.AsMemory());
if (bytesRead == 0)
break;
// Process the data using Span without unnecessary copying
ProcessData(buffer.AsSpan(0, bytesRead));
}
}
}
static void ProcessData(Span<byte> data)
{
// Perform operations on the data
}
}
using System;
using System.IO;
using System.Threading.Tasks;
class Program
{
static async Task ProcessFileAsync(string filePath)
{
const int bufferSize = 4096;
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[bufferSize];
while (true)
{
int bytesRead = await fileStream.ReadAsync(buffer.AsMemory());
if (bytesRead == 0)
break;
// Process the data using Span without unnecessary copying
ProcessData(buffer.AsSpan(0, bytesRead));
}
}
}
static void ProcessData(Span<byte> data)
{
// Perform operations on the data
}
}
Imports System
Imports System.IO
Imports System.Threading.Tasks
Friend Class Program
Private Shared Async Function ProcessFileAsync(ByVal filePath As String) As Task
Const bufferSize As Integer = 4096
Using fileStream As New FileStream(filePath, FileMode.Open, FileAccess.Read)
Dim buffer(bufferSize - 1) As Byte
Do
Dim bytesRead As Integer = Await fileStream.ReadAsync(buffer.AsMemory())
If bytesRead = 0 Then
Exit Do
End If
' Process the data using Span without unnecessary copying
ProcessData(buffer.AsSpan(0, bytesRead))
Loop
End Using
End Function
Private Shared Sub ProcessData(ByVal data As Span(Of Byte))
' Perform operations on the data
End Sub
End Class
Ici, la méthode ReadAsync lit des données d'un flux de fichier dans le tampon, et la méthode ProcessData traite les données directement à partir de Span
3. Traitement de tâches asynchrones :
Lorsque vous travaillez avec des tâches asynchrones qui produisent ou consomment des données, vous pouvez utiliser Memory
using System;
using System.Linq;
using System.Threading.Tasks;
class Program
{
static async Task<int> ProcessDataAsync(int[] data)
{
// Asynchronous processing of data
await Task.Delay(1000);
// Returning the length of the processed data
return data.Length;
}
static async Task Main()
{
int[] inputData = Enumerable.Range(1, 1000).ToArray();
// Process the data asynchronously without copying
int processedLength = await ProcessDataAsync(inputData.AsMemory());
Console.WriteLine($"Processed data length: {processedLength}");
}
}
using System;
using System.Linq;
using System.Threading.Tasks;
class Program
{
static async Task<int> ProcessDataAsync(int[] data)
{
// Asynchronous processing of data
await Task.Delay(1000);
// Returning the length of the processed data
return data.Length;
}
static async Task Main()
{
int[] inputData = Enumerable.Range(1, 1000).ToArray();
// Process the data asynchronously without copying
int processedLength = await ProcessDataAsync(inputData.AsMemory());
Console.WriteLine($"Processed data length: {processedLength}");
}
}
Imports System
Imports System.Linq
Imports System.Threading.Tasks
Friend Class Program
Private Shared Async Function ProcessDataAsync(ByVal data() As Integer) As Task(Of Integer)
' Asynchronous processing of data
Await Task.Delay(1000)
' Returning the length of the processed data
Return data.Length
End Function
Shared Async Function Main() As Task
Dim inputData() As Integer = Enumerable.Range(1, 1000).ToArray()
' Process the data asynchronously without copying
Dim processedLength As Integer = Await ProcessDataAsync(inputData.AsMemory())
Console.WriteLine($"Processed data length: {processedLength}")
End Function
End Class
Dans cet exemple, la méthode ProcessDataAsync traite les données de manière asynchrone et renvoie la longueur des données traitées sans nécessiter de copies supplémentaires.
Présentation d'IronPDF
Overview de la bibliothèque IronPDF est la dernière bibliothèque PDF C# de Iron Software qui peut être utilisée pour générer dynamiquement de magnifiques documents PDF à la volée en utilisant du code C#. IronPDF fournit une variété de fonctionnalités telles que la génération de PDF à partir de HTML, la conversion de contenu HTML en PDF, la fusion ou la division de fichiers PDF, etc.
La fonctionnalité principale d'IronPDF est sa fonctionnalité HTML en PDF, qui préserve les mises en page et les styles. Il peut générer des PDF à partir de contenu web, ce qui le rend idéal pour des rapports, des factures et de la documentation. Cet outil prend en charge la conversion de fichiers HTML, d'URL et de chaînes HTML en fichiers PDF.
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
// 1. Convert HTML String to PDF
var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");
// 2. Convert HTML File to PDF
var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");
// 3. Convert URL to PDF
var url = "http://ironpdf.com"; // Specify the URL
var pdfFromUrl = renderer.RenderUrlAsPdf(url);
pdfFromUrl.SaveAs("URLToPDF.pdf");
}
}
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
// 1. Convert HTML String to PDF
var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");
// 2. Convert HTML File to PDF
var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");
// 3. Convert URL to PDF
var url = "http://ironpdf.com"; // Specify the URL
var pdfFromUrl = renderer.RenderUrlAsPdf(url);
pdfFromUrl.SaveAs("URLToPDF.pdf");
}
}
Imports IronPdf
Friend Class Program
Shared Sub Main(ByVal args() As String)
Dim renderer = New ChromePdfRenderer()
' 1. Convert HTML String to PDF
Dim htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>"
Dim pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent)
pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf")
' 2. Convert HTML File to PDF
Dim htmlFilePath = "path_to_your_html_file.html" ' Specify the path to your HTML file
Dim pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath)
pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf")
' 3. Convert URL to PDF
Dim url = "http://ironpdf.com" ' Specify the URL
Dim pdfFromUrl = renderer.RenderUrlAsPdf(url)
pdfFromUrl.SaveAs("URLToPDF.pdf")
End Sub
End Class
Installation
IronPDF peut être installé en utilisant le gestionnaire de packages NuGet pour IronPDF ou en utilisant le gestionnaire de packages de Visual Studio.
dotnet add package IronPdf // Or Install-Package IronPdf

using System;
using IronPdf;
class Program
{
static void Main()
{
Console.WriteLine("Generating PDF using IronPDF.");
var displayFirstName = "<p>First Name is Joe</p>".AsSpan();
var displayLastName = "<p>Last Name is Doe</p>".AsSpan();
var displayAddress = "<p>12th Main, 7Th Cross, New York</p>".AsSpan();
var start = "<html><body>".AsSpan();
var end = "</body></html>".AsSpan();
var content = string.Concat(start.ToString(), displayFirstName.ToString(), displayLastName.ToString(), displayAddress.ToString(), end.ToString());
var pdfDocument = new ChromePdfRenderer();
pdfDocument.RenderHtmlAsPdf(content).SaveAs("span.pdf");
}
}
using System;
using IronPdf;
class Program
{
static void Main()
{
Console.WriteLine("Generating PDF using IronPDF.");
var displayFirstName = "<p>First Name is Joe</p>".AsSpan();
var displayLastName = "<p>Last Name is Doe</p>".AsSpan();
var displayAddress = "<p>12th Main, 7Th Cross, New York</p>".AsSpan();
var start = "<html><body>".AsSpan();
var end = "</body></html>".AsSpan();
var content = string.Concat(start.ToString(), displayFirstName.ToString(), displayLastName.ToString(), displayAddress.ToString(), end.ToString());
var pdfDocument = new ChromePdfRenderer();
pdfDocument.RenderHtmlAsPdf(content).SaveAs("span.pdf");
}
}
Imports System
Imports IronPdf
Friend Class Program
Shared Sub Main()
Console.WriteLine("Generating PDF using IronPDF.")
Dim displayFirstName = "<p>First Name is Joe</p>".AsSpan()
Dim displayLastName = "<p>Last Name is Doe</p>".AsSpan()
Dim displayAddress = "<p>12th Main, 7Th Cross, New York</p>".AsSpan()
Dim start = "<html><body>".AsSpan()
Dim [end] = "</body></html>".AsSpan()
Dim content = String.Concat(start.ToString(), displayFirstName.ToString(), displayLastName.ToString(), displayAddress.ToString(), [end].ToString())
Dim pdfDocument = New ChromePdfRenderer()
pdfDocument.RenderHtmlAsPdf(content).SaveAs("span.pdf")
End Sub
End Class
Dans cet exemple, nous utilisons Span avec IronPDF pour générer un document PDF.
Sortie :

PDF généré :

Licence (Essai Gratuit Disponible)
Informations sur la licence IronPDF. Cette clé doit être placée dans appsettings.json.
"IronPdf.LicenseKey": "your license key"
Fournissez votre email pour obtenir une licence d'essai.
Conclusion
Span
Veuillez visiter la page page de documentation rapide de démarrage d'IronPDF.
Questions Fréquemment Posées
Qu'est-ce que Span en C# et pourquoi est-ce important ?
Span est un type introduit dans C# 7.2 qui représente une région contiguë de mémoire. Il est important car il permet aux développeurs d'effectuer efficacement des opérations de mémoire à bas niveau sans les frais d'allocations de tas, maintenant la sécurité et la performance de C#.
Comment Span optimise-t-il la manipulation de la mémoire en C# ?
Span optimise la manipulation de la mémoire en fournissant une abstraction zéro-copie sur la mémoire, permettant aux développeurs de référencer des blocs de mémoire existants sans dupliquer les données. Cela conduit à des améliorations de performance, en particulier dans les applications qui manipulent de grands volumes de données.
Quelle est la différence entre Span et ReadOnlySpan ?
Span est une vue mutable de la mémoire, permettant des modifications, tandis que ReadOnlySpan fournit une vue en lecture seule. ReadOnlySpan est utilisé lorsque les données ne doivent pas être modifiées, offrant des avantages de performance similaires tout en garantissant l'intégrité des données.
Span peut-il être utilisé avec la mémoire non gérée en C# ?
Oui, Span peut être utilisé avec la mémoire non gérée en créant un span à partir d'un pointeur vers la mémoire non gérée. Cela permet une manipulation directe de la mémoire tout en s'assurant qu'elle est correctement allouée et désallouée en utilisant des méthodes comme Marshal.AllocHGlobal et Marshal.FreeHGlobal.
Comment IronPDF s'intègre-t-il avec Span pour la génération de PDF ?
IronPDF peut fonctionner aux côtés de Span pour générer des PDF dynamiquement en gérant efficacement la mémoire et en évitant les allocations inutiles. Cette intégration permet aux développeurs de créer des documents PDF à partir de contenu Web avec une meilleure performance.
Quelles sont les limitations de l'utilisation de Span pour la gestion de la mémoire ?
Les limitations de l'utilisation de Span incluent l'exigence d'une mémoire contiguë, l'absence de gestion automatique de la mémoire et de collecte des ordures, et aucun support pour la mémoire non contiguë. Les développeurs doivent manuellement s'assurer de la validité de la mémoire et des limites.
Comment peut-on installer IronPDF pour la manipulation de PDF en C# ?
IronPDF peut être installé dans un projet C# en utilisant le Package Manager NuGet. Utilisez des commandes telles que dotnet add package IronPDF ou Install-Package IronPDF pour l'ajouter à votre projet.
Quels sont les avantages de l'utilisation de Span pour la manipulation de chaînes ?
Span permet une manipulation efficace des chaînes en minimisant les allocations de mémoire et les copies. Cela est particulièrement bénéfique dans le code critique pour la performance où de grandes quantités de données de chaîne sont traitées.
Y a-t-il une version d'essai disponible pour IronPDF?
Oui, IronPDF propose une licence d'essai qui peut être obtenue en fournissant votre adresse email. La clé de licence d'essai doit être placée dans le fichier appsettings.json pour utiliser la bibliothèque.
Span peut-il être utilisé dans des appels de méthodes asynchrones ?
Oui, Span peut être utilisé dans des appels de méthodes asynchrones pour traiter les données efficacement sans copie inutile. Cela est particulièrement utile dans les opérations d'E/S et le traitement de fichiers, en tirant parti de Memory ou Span.




