AIDE .NET

C# Span (Comment ça marche pour les développeurs)

Publié mars 6, 2024
Partager:

Span est un type introduit en C# 7.2 dans le cadre du Spandans l'espace de noms System. Il est conçu pour représenter une région contiguë d'une mémoire arbitraire. Contrairement aux tableaux ou aux collections telles que le tas géré, Span ne possède pas la mémoire de la pile ou la région de la mémoire vers laquelle il pointe ; au lieu de cela, il fournit une vue légère sur les blocs de mémoire existants. Cette caractéristique rend Span particulièrement puissant pour les scénarios dans lesquels vous avez besoin de travailler efficacement avec des tampons de mémoire sans encourir de frais généraux supplémentaires et de scénarios de code peu sûrs. Plus loin dans cet article, nous verrons également l'introduction de IronPDF bibliothèque de Iron Software.

Principales caractéristiques de la portée

1. Gestion de la mémoire

Span en C# permet aux développeurs de travailler directement avec la mémoire sans avoir recours aux allocations traditionnelles du tas. Il permet 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 les plus remarquables de C# Span est l'absence de copie des abstractions. Au lieu de dupliquer les données, Span permet de référencer efficacement la mémoire existante. Cela est particulièrement utile dans les cas où la copie de grandes quantités de données ne serait pas pratique ou trop coûteuse.

3. Opérations de type pointeur

Alors que C# est traditionnellement un langage sûr de haut niveau, Span introduit un certain degré de manipulation de la mémoire de bas niveau, semblable à l'utilisation de pointeurs dans des langages tels que C ou C++. Les développeurs peuvent effectuer des opérations de type pointeur sans sacrifier la sécurité et la nature gérée de C#.

4. Nature immuable

Malgré ses possibilités d'accès à la mémoire de bas niveau, C# Span reste immuable. Cela signifie que, tout en permettant la manipulation de la mémoire, il assure la sécurité en empêchant les modifications involontaires.

Exemple

using System;
class Program
{
    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
{
    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
	Private 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
VB   C#

ReadOnlySpan

Alors que le Spanest mutable et permet de modifier les données sous-jacentes, ReadOnlySpanest une vue immuable de la mémoire. Il fournit une interface en lecture seule à une région contiguë de la mémoire, ce qui le rend adapté aux scénarios dans lesquels vous n'avez besoin que de lire les données sans les modifier.

Voici quelques points clés.

1. Vue en lecture seule

Comme son nom l'indique, ReadOnlySpanpermet de créer une vue en lecture seule d'un bloc de mémoire. Cela signifie que vous ne pouvez pas modifier les éléments par le biais d'un ReadOnlySpan.

2. Représentation de la mémoire

Comme Span, ReadOnlySpanne possède pas la mémoire vers laquelle il pointe. Il fait référence à la mémoire existante et peut pointer vers des tableaux, de la mémoire allouée par pile ou de la mémoire native.

3. Avantages en termes de performance

Comme Span, ReadOnlySpanpeut offrir de meilleures performances que les types de collecte traditionnels, en particulier lorsqu'il s'agit de traiter de grandes quantités de données, car il réduit le besoin de copie.

4. Contrôle sans limite

Comme pour Span, ReadOnlySpann'effectue pas de contrôle des limites. Il incombe au développeur de veiller à ce que les opérations restent dans les limites de la mémoire sous-jacente.

5. Utilisation avec Array Slicing

ReadOnlySpanprend en charge le découpage en tranches, ce qui permet de créer des sous-domaines qui font référence à une partie de la mémoire d'origine.

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
VB   C#

Il existe de nombreuses façons de créer et d'utiliser ReadOnlySpan. Voici quelques exemples.

1. Création d'un 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
VB   C#

2. Travailler avec des sous-chaînes

Utiliser Slice sur le ReadOnlySpan

ReadOnlySpan<char> substringSpan = spanFromString.Slice(startIndex, length);
ReadOnlySpan<char> substringSpan = spanFromString.Slice(startIndex, length);
Dim substringSpan As ReadOnlySpan(Of Char) = spanFromString.Slice(startIndex, length)
VB   C#

3. Transmettre une chaîne de caractères à une méthode

Pass ReadOnlySpancomme paramètre de la méthode.

void ProcessSubstringfromReadOnlySpan(ReadOnlySpan<char> substring)
{
    // Perform operations on the substring
}
// Usage
ProcessSubstringfromReadOnlySpan(spanFromString.Slice(startIndex, length));
void ProcessSubstringfromReadOnlySpan(ReadOnlySpan<char> substring)
{
    // Perform operations on the substring
}
// Usage
ProcessSubstringfromReadOnlySpan(spanFromString.Slice(startIndex, length));
Private Sub ProcessSubstringfromReadOnlySpan(ByVal substring As ReadOnlySpan(Of Char))
	' Perform operations on the substring
End Sub
' Usage
ProcessSubstringfromReadOnlySpan(spanFromString.Slice(startIndex, length))
VB   C#

4. Recherche dans une chaîne de caractères

ReadOnlySpanpour la recherche à l'intérieur d'une chaîne avec IndexOf().

int index = stringSpan.IndexOf('W');
int index = stringSpan.IndexOf('W');
Dim index As Integer = stringSpan.IndexOf("W"c)
VB   C#

5. Utilisation de fichiers en mémoire

ReadOnlySpanpeut être plus efficace avec les fichiers en mémoire.

using (var memmf = MemoryMappedFile.CreateFromFile("data.bin"))
{
    using (var accessor = memmf.CreateViewAccessor())
    {
        ReadOnlySpan<byte> dataSpan;
        accessor.Read(0, out dataSpan);
        // Process data directly from the memory-mapped file
        ProcessData(dataSpan);
    }
}
using (var memmf = MemoryMappedFile.CreateFromFile("data.bin"))
{
    using (var accessor = memmf.CreateViewAccessor())
    {
        ReadOnlySpan<byte> dataSpan;
        accessor.Read(0, out dataSpan);
        // Process data directly from the memory-mapped file
        ProcessData(dataSpan);
    }
}
Using memmf = MemoryMappedFile.CreateFromFile("data.bin")
	Using accessor = memmf.CreateViewAccessor()
		Dim dataSpan As ReadOnlySpan(Of Byte) = Nothing
		accessor.Read(0, dataSpan)
		' Process data directly from the memory-mapped file
		ProcessData(dataSpan)
	End Using
End Using
VB   C#

6. Manipulation efficace des chaînes de caractères

ReadOnlySpanpeut être utilisé pour une manipulation efficace des chaînes de caractères.

// Replace a character in a substring without creating a new string
spanFromString.Slice(startIndex, length).CopyTo(newSpan);
// Replace a character in a substring without creating a new string
spanFromString.Slice(startIndex, length).CopyTo(newSpan);
' Replace a character in a substring without creating a new string
spanFromString.Slice(startIndex, length).CopyTo(newSpan)
VB   C#

7. Transmettre une chaîne de caractères aux API

Lorsque vous travaillez avec des bibliothèques ou des API externes qui fonctionnent sur des plages de caractères.

void ExternalApiMethod(ReadOnlySpan<char> data)
{
    // Call the external API with the character span
}
// Usage
ExternalApiMethod(spanFromString.Slice(startIndex, length));
void ExternalApiMethod(ReadOnlySpan<char> data)
{
    // Call the external API with the character span
}
// Usage
ExternalApiMethod(spanFromString.Slice(startIndex, length));
Private Sub ExternalApiMethod(ByVal data As ReadOnlySpan(Of Char))
	' Call the external API with the character span
End Sub
' Usage
ExternalApiMethod(spanFromString.Slice(startIndex, length))
VB   C#

ReadOnlySpanpermet de travailler plus efficacement avec les chaînes de caractères, en particulier dans les scénarios où l'allocation et la copie de mémoire doivent être réduites au minimum. Il s'agit d'un outil puissant pour l'optimisation des codes critiques en termes de performances, qui peut s'avérer particulièrement utile lorsqu'il s'agit de traiter de grandes quantités de données sous forme de chaînes de caractères.

Limitations de la portée

Si la portée en C# est une fonctionnalité puissante qui présente de nombreux avantages, elle s'accompagne de certaines limitations et considérations, notamment dans le contexte de la mémoire contiguë et non contiguë. Explorons ces limites :

1. Tampons de mémoire contigus

1.1 Pas de gestion automatique de la mémoire

La portéene gère pas la mémoire vers laquelle il pointe. Cela signifie que si la mémoire gérée sous-jacente est libérée ou sort du champ d'application, l'utilisation de la méthode Spanentraînera un comportement indéfini ou des pannes potentielles. Les développeurs doivent s'assurer que la mémoire sous-jacente est toujours valide lors de l'utilisation d'un Span.

1.2 Pas de collecte d'ordures

Puisque Spanne possède pas de mémoire, il n'est pas soumis au ramassage des ordures. Par conséquent, vous devez être prudent lorsque vous travaillez avec de la mémoire allouée par pile ou de la mémoire dont la durée de vie est plus courte que celle de la mémoire Spanmême.

1.3 Le contrôle des limites est désactivé

La portéeet ReadOnlyLa portéen'effectuent pas de contrôle des limites par défaut. Si elle n'est pas utilisée avec précaution, elle peut conduire à l'accès à des emplacements de mémoire non valides. Les développeurs doivent s'assurer manuellement que les opérations sur un Spanrester dans les limites de la mémoire sous-jacente.

1.4 Pas de prise en charge de la mémoire non contiguë

La portéeest conçu pour fonctionner avec une mémoire contiguë. Si vous disposez d'une mémoire non contiguë ou si vous devez représenter des structures de données plus complexes, Spann'est peut-être pas le choix le plus approprié.

1.5 Toutes les opérations ne sont pas prises en charge

Alors que le Spanprend en charge de nombreuses opérations courantes telles que le découpage, l'indexation et l'itération, mais toutes les opérations ne sont pas prises en charge. Par exemple, vous ne pouvez pas redimensionner un Spanet certaines opérations qui impliquent de modifier la longueur de la mémoire sous-jacente ne sont pas autorisées.

1.6 Compatibilité limitée des plates-formes

Alors que le Spanfait partie du Standard .NET et de .NET Core, il peut ne pas être disponible sur toutes les plateformes ou dans tous les environnements. Il est essentiel de s'assurer que votre plateforme cible prend en charge Spansi vous prévoyez de l'utiliser dans votre code.

2. Tampons de mémoire non contigus

2.1 Prise en charge limitée de la mémoire non contiguë

ReadOnlySpanest principalement conçu pour fonctionner de manière transparente avec des blocs de mémoire contigus ou des tampons. Ce n'est peut-être pas le choix le plus approprié pour les scénarios où des tampons de mémoire non contigus ou des structures avec des trous de mémoire sont impliqués.

2.2 Limites structurelles

Certaines structures de données ou certains scénarios reposant sur une mémoire non contiguë peuvent ne pas être compatibles avec ReadOnlySpan. Par exemple, les structures de données telles que les listes chaînées ou les structures graphiques peuvent ne pas être bien adaptées en raison de l'exigence de mémoire contiguë de ReadOnlySpan.

2.3 Opérations complexes sur les pointeurs

Dans les situations impliquant une mémoire non contiguë, en particulier celles qui nécessitent une arithmétique de pointeurs complexe, ReadOnlySpanpourrait ne pas offrir le même contrôle de bas niveau et la même flexibilité que les pointeurs bruts dans des langages comme le C#. Dans ce cas, l'utilisation d'un code non sécurisé avec des pointeurs peut s'avérer plus appropriée.

2.4 Absence de prise en charge directe dans certaines API

Comme pour la mémoire contiguë, il est important de noter que toutes les API ou bibliothèques ne prennent pas directement en charge la mémoire non contiguë représentée par ReadOnlySpan. L'adaptation à de tels scénarios peut nécessiter des étapes intermédiaires supplémentaires ou des conversions pour assurer la compatibilité.

Span et mémoire non gérée

En C#, Span peut être utilisé efficacement avec 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 ramasse-miettes du moteur d'exécution .NET et implique souvent l'utilisation d'allocations et de désallocations de mémoire natives. Voici comment Span peut être utilisé avec la mémoire non gérée en C#.

Allocation de 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 sur le bloc alloué. La mémoire allouée ou l'adresse de la mémoire est conservée dans un pointeurMemory non géré et sera accessible en lecture-écriture. Les régions contiguës de la mémoire sont 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
VB   C#

Dans le code source ci-dessus, nous allouons un bloc de mémoire non géré à l'aide de Marshal.AllocHGlobal, puis nous créons un Spanen utilisant le pointeur obtenu à partir de la mémoire non gérée. Cela nous permet de travailler avec une mémoire non gérée en utilisant l'API Span qui nous est familière. Il est important de noter que lorsque vous travaillez avec de la mémoire non gérée, vous êtes responsable de la gestion de l'allocation et de la désallocation de la mémoire.

Copie de données vers et depuis une mémoire non gérée

Span fournit des méthodes telles que 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 = MemoryMarshal.Allocate<int>(sourceArray.Length);
        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 = MemoryMarshal.Cast<int, byte>(destinationPointer, 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
            MemoryMarshal.Free(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 = MemoryMarshal.Allocate<int>(sourceArray.Length);
        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 = MemoryMarshal.Cast<int, byte>(destinationPointer, 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
            MemoryMarshal.Free(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 = MemoryMarshal.Allocate(Of Integer)(sourceArray.Length)
		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 Span(Of Integer) = MemoryMarshal.Cast(Of Integer, Byte)(destinationPointer, 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
			MemoryMarshal.Free(destinationPointer)
		End Try
	End Sub
End Class
VB   C#

Dans cet exemple :

MemoryMarshal.Allocate(sourceArray.Length) alloue de la mémoire non gérée pour les données de destination. MemoryMarshal.Cast<int, byte>(destinationPointer, sourceArray.Length) crée un Spanà partir de la mémoire non gérée allouée. Le paramètre sourceSpan.CopyTo(destinationSpan) copie les données du tableau géré dans la mémoire non gérée. Les valeurs de la mémoire de destination sont imprimées pour vérifier l'opération de copie. Le maréchal de la mémoire.gratuit(destinationPointer) est utilisée pour désallouer la mémoire non gérée.

Utilisation de code non sécurisé

Lorsque vous manipulez de la mémoire non gérée, vous pouvez également utiliser du code non sécurisé avec des pointeurs. Dans ce cas, vous pouvez obtenir un pointeur à partir du Span en utilisant la méthode Unsafe.AsPointer() méthode.

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 unsafe code to work with pointers
        // ref t
        unsafe
        {
            byte* pointer = (byte*)Unsafe.AsPointer(ref struct 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;
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
        // ref t
        unsafe
        {
            byte* pointer = (byte*)Unsafe.AsPointer(ref struct 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
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
		' ref t
'INSTANT VB TODO TASK: C# 'unsafe' code is not converted by Instant VB:
'		unsafe
'		{
'			byte* pointer = (byte*)Unsafe.AsPointer(ref struct 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
VB   C#

Dans cet exemple, nous utilisons la méthode Unsafe.AsPointer pour obtenir un pointeur du Span. Cela nous permet d'utiliser du code non sécurisé lorsque nous travaillons directement avec des pointeurs.

N'oubliez pas que lorsque vous travaillez avec de la mémoire non gérée, il est essentiel de gérer correctement l'allocation et la désallocation afin d'éviter les fuites de mémoire. Libérez toujours la mémoire non gérée à l'aide de méthodes appropriées, telles que Marshal.FreeHGlobal(). En outre, soyez prudent lorsque vous utilisez du code non sécurisé, car il peut présenter des risques potentiels pour la sécurité s'il n'est pas traité correctement.

Span et appels de méthodes asynchrones

L'utilisation de Span en conjonction avec des appels de méthodes asynchrones en C# est une combinaison puissante, en particulier lorsqu'il s'agit de grandes quantités de données ou d'opérations d'E/S. L'objectif est de traiter efficacement les opérations asynchrones sans copie inutile des données. Voyons comment vous pouvez tirer parti de Span dans des scénarios asynchrones :

1. Opérations d'E/S asynchrones:

Lors d'opérations d'E/S asynchrones, telles que la lecture ou l'écriture de données dans un flux, vous pouvez utiliser Memoryou Spanpour travailler efficacement avec les données sans créer de tampons supplémentaires.

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));
    }
}
void ProcessData(Span<byte> data)
{
    // Perform operations on the data
}
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));
    }
}
void ProcessData(Span<byte> data)
{
    // Perform operations on the data
}
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 Sub ProcessData(ByVal data As Span(Of Byte))
	' Perform operations on the data
End Sub
VB   C#

Dans cet exemple, la méthode ReadAsync lit de manière asynchrone les données d'un flux dans la mémoire tampon. La méthode ProcessData traite ensuite les données directement à partir du Spansans le copier dans un autre tampon.

2. Opérations de fichiers asynchrones:

Comme pour les opérations d'entrée/sortie, vous pouvez utiliser Span pour traiter efficacement les données sans copie supplémentaire lors des opérations de fichiers asynchrones.

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));
        }
    }
}
void ProcessData(Span<byte> data)
{
    // Perform operations on the data
}
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));
        }
    }
}
void ProcessData(Span<byte> data)
{
    // Perform operations on the data
}
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 Sub ProcessData(ByVal data As Span(Of Byte))
	' Perform operations on the data
End Sub
VB   C#

Ici, la méthode ReadAsync lit les données d'un flux de fichiers dans la mémoire tampon, et la méthode ProcessData traite les données directement à partir du Span.

3. Traitement des tâches asynchrones:

Lorsque vous travaillez avec des tâches asynchrones qui produisent ou consomment des données, vous pouvez utiliser Memoryou Spanafin d'éviter les copies inutiles.

async Task<int> ProcessDataAsync(int [] data)
{
    // Asynchronous processing of data
    await Task.Delay(1000);
    // Returning the length of the processed data
    return data.Length;
}
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}");
}
async Task<int> ProcessDataAsync(int [] data)
{
    // Asynchronous processing of data
    await Task.Delay(1000);
    // Returning the length of the processed data
    return data.Length;
}
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}");
}
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
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
VB   C#

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

IronPDF est la dernière bibliothèque PDF C# de Iron Software qui peut être utilisé pour générer de beaux documents PDF à la volée de manière dynamique à l'aide du code C#. IronPDF offre de nombreuses 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 principale caractéristique d'IronPDF est son HTML à PDF qui préserve les mises en page et les styles. Il peut générer des PDF à partir de contenus web, ce qui en fait un outil idéal pour les rapports, les factures et la documentation. Cet outil permet de convertir des fichiers HTML, des URL et des 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
VB   C#

Installation

IronPDF peut être installé à l'aide de la commande NuGet Ou en utilisant le gestionnaire de paquets de Visual Studio.

dotnet add package IronPdf
// Or
Install-Package IronPdf
dotnet add package IronPdf
// Or
Install-Package IronPdf
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'dotnet add package IronPdf Install-Package IronPdf
VB   C#

C# Span (Comment ça marche pour les développeurs) : Figure 1 - Installer IronPDF à l'aide du NuGet Package Manager en recherchant "ironpdf" ; dans la barre de recherche du NuGet Package Manager

using System;
class Program
{
    static void Main()
    {
        Console.WriteLine("Generating PDF using IronPDF.");
        var displayFirstName = "<p>First Name is Joe</p>".AsSpan();
        var displayLastName = "<p>First Name is Doe</p>".AsSpan();
        var displayAddress = "<p>12th Main, 7Th Cross, New York</p>".AsSpan();
        var start = @"<!DOCTYPE html>
<html>
<body>".AsSpan();
        var end = @"<!DOCTYPE html>
<html>
<body>";
        var content = string.Concat(start, displayFirstName, displayLastName, string.Concat(displayAddress, end));
        var pdfDocument = new ChromePdfRenderer();
        pdfDocument.RenderHtmlAsPdf(content).SaveAs("span.pdf");
    }
}
using System;
class Program
{
    static void Main()
    {
        Console.WriteLine("Generating PDF using IronPDF.");
        var displayFirstName = "<p>First Name is Joe</p>".AsSpan();
        var displayLastName = "<p>First Name is Doe</p>".AsSpan();
        var displayAddress = "<p>12th Main, 7Th Cross, New York</p>".AsSpan();
        var start = @"<!DOCTYPE html>
<html>
<body>".AsSpan();
        var end = @"<!DOCTYPE html>
<html>
<body>";
        var content = string.Concat(start, displayFirstName, displayLastName, string.Concat(displayAddress, end));
        var pdfDocument = new ChromePdfRenderer();
        pdfDocument.RenderHtmlAsPdf(content).SaveAs("span.pdf");
    }
}
Imports System
Friend Class Program
	Shared Sub Main()
		Console.WriteLine("Generating PDF using IronPDF.")
		Dim displayFirstName = "<p>First Name is Joe</p>".AsSpan()
		Dim displayLastName = "<p>First Name is Doe</p>".AsSpan()
		Dim displayAddress = "<p>12th Main, 7Th Cross, New York</p>".AsSpan()
		Dim start = "<!DOCTYPE html>
<html>
<body>".AsSpan()
		Dim [end] = "<!DOCTYPE html>
<html>
<body>"
		Dim content = String.Concat(start, displayFirstName, displayLastName, String.Concat(displayAddress, [end]))
		Dim pdfDocument = New ChromePdfRenderer()
		pdfDocument.RenderHtmlAsPdf(content).SaveAs("span.pdf")
	End Sub
End Class
VB   C#

Dans cet exemple, nous utilisons Span avec IronPDF pour générer un document PDF.

Output:

C# Span (Comment ça marche pour les développeurs) : Figure 2 - Sortie de la console

PDF généré:

C# Span (Comment ça marche pour les développeurs) : Figure 3 - Sortie PDF

Licence (essai gratuit disponible)

IronPDF. Cette clé doit être placée dans appsettings.json.

"IronPdf.LicenseKey": "your license key"
"IronPdf.LicenseKey": "your license key"
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'"IronPdf.LicenseKey": "your license key"
VB   C#

Indiquez votre adresse électronique pour obtenir une licence d'essai.

Conclusion

La portéeen C# constitue un moyen puissant et efficace de travailler avec la mémoire, offrant des avantages en termes de performances et de flexibilité. Sa nature non propriétaire et contiguë la rend particulièrement adaptée aux scénarios dans lesquels il est crucial de minimiser les allocations et les copies de mémoire. En tirant parti de Span, les développeurs peuvent améliorer les performances de toute une série d'applications, allant de la manipulation de chaînes de caractères au traitement numérique haute performance. En comprenant ses caractéristiques et en tenant compte de ses limites, les développeurs peuvent tirer parti de Spanpour effectuer diverses tâches de manipulation de la mémoire de manière sûre et efficace. Avec IronPDFil peut être utilisé pour générer d'excellents documents PDF sans attente et sans limite de rendement.

En plus de la essai gratuit pour une utilisation à long terme. Pour en savoir plus sur l'utilisation d'IronPDF, veuillez visiter leur site web la documentation page.

< PRÉCÉDENT
IDE C# (Comment ça marche pour les développeurs)
SUIVANT >
Opentelemetry C# (Comment ça marche pour les développeurs)