C# Span (Funktionsweise für Entwickler)
Span ist ein Typ, der in C# 7.2 als Teil der Span-Struktur im System-Namespace eingeführt wurde. Er ist dafür ausgelegt, einen zusammenhängenden Bereich von beliebigem Speicher darzustellen. Anders als Arrays oder Sammlungen wie der verwaltete Heap besitzt Span nicht den Stack-Speicher oder den Speicherbereich, auf den es verweist; stattdessen bietet es eine schlanke Ansicht über bestehende Speicherblöcke. Dieses Merkmal macht Span besonders leistungsfähig für Szenarien, in denen Sie effizient mit Speicherpuffern arbeiten müssen, ohne zusätzlichen Overhead und unsicherem Code-Szenarien. Später in diesem Artikel werden wir auch die Einführung in die IronPDF-Bibliothek von Iron Software sehen.
Schlüsselmerkmale von Span
1. Speicherverwaltung
Span in C# ermöglicht es Entwicklern, direkt mit Speicher zu arbeiten, ohne auf traditionelle Heap-Allokationen zurückgreifen zu müssen. Es bietet eine Möglichkeit, Speicherabschnitte aus bestehenden Arrays oder anderen Speicherquellen zu erstellen und somit zusätzlichen Speicher mit Kopien zu vermeiden.
2. Kopierfreie Abstraktionen
Eines der herausragenden Merkmale von C# Span sind seine Zero-Copy-Abstraktionen. Anstatt Daten zu duplizieren, bietet Span einen Weg, um bestehenden Speicher effizient zu referenzieren. Dies ist besonders vorteilhaft für Szenarien, in denen das Kopieren großer Datenmengen unpraktisch oder zu kostspielig wäre.
3. Zeigerähnliche Operationen
Auch wenn C# traditionell eine hochstufige, sichere Sprache war, führt Span ein gewisses Maß an Low-Level-Speichermanipulation ein, ähnlich wie bei der Arbeit mit Zeigern in Sprachen wie C oder C++. Entwickler können zeigerähnliche Operationen durchführen, ohne die Sicherheit und Verwaltbarkeit von C# zu opfern.
4. Unveränderliche Natur
Trotz seiner Fähigkeiten für Low-Level-Speicherzugriff bleibt C# Span unveränderlich. Das bedeutet, dass es zwar die Manipulation von Speicher erlaubt, aber die Sicherheit gewährleistet, indem es unbeabsichtigte Änderungen verhindert.
Beispiel
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
Während Span
Hier sind einige wichtige Punkte.
1. Nur-Lese-Ansicht
Wie der Name schon sagt, ermöglicht ReadOnlySpan
2. Die Darstellung des Speichers
Wie Span
3. Leistungsbezogene Vorteile
Wie Span
4. Keine Prüfung von Grenzen
Wie bei Span
5. Verwendung mit Array Slicing
ReadOnlySpan
Beispiel
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
Es gibt viele verschiedene Möglichkeiten, ReadOnlySpan zu erstellen und damit zu arbeiten. Nachfolgend einige Beispiele.
1. Erstellen von ReadOnlySpan aus String
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. Mit Teilstrings arbeiten
Verwenden Sie Slice auf dem 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. Die Übergabe einer Zeichenkette an eine Methode
Übergeben Sie 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. Suche innerhalb einer Zeichenkette
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. Verwendung von Memory-Mapped-Dateien
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. Effiziente String-Manipulation
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. Die Übergabe einer Zeichenkette an APIs
Bei der Arbeit mit externen Bibliotheken oder APIs, die mit Zeichenbereichen arbeiten.
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
Beschränkungen des Umfangs
Während Span in C# ein leistungsstarkes Merkmal mit zahlreichen Vorteilen ist, gibt es bestimmte Einschränkungen und Überlegungen, insbesondere im Kontext von zusammenhängendem und nicht zusammenhängendem Speicher. Schauen wir uns diese Einschränkungen an:
1. Zusammenhängende Speicherpuffer
1.1 Keine automatische Speicherverwaltung
Span verwaltet den Speicher, auf den es zeigt, nicht. Das bedeutet, dass, wenn der zugrunde liegende verwaltete Speicher freigegeben oder außer Scope gerät, die Verwendung von Span
1.2 Keine Garbage Collection
Da Span
1.3 Überprüfung der Grenzen ist deaktiviert
Span
1.4 Keine Unterstützung für nicht-zusammenhängenden Speicher
Span
1.5 Nicht alle Operationen werden unterstützt
Während Span
1.6 Eingeschränkte Plattformkompatibilität
Obwohl Span
2. nicht-zusammenhängende Speicherpuffer
2.1 Begrenzte Unterstützung für nicht zusammenhängenden Speicher
ReadOnlySpan
2.2 Strukturelle Beschränkungen
Bestimmte Datenstrukturen oder Szenarien, die auf nicht zusammenhängenden Speicher angewiesen sind, passen möglicherweise nicht gut zu ReadOnlySpan
2.3 Komplexe Zeigeroperationen
In Situationen, die nicht zusammenhängenden Speicher betreffen, insbesondere bei solchen, die komplizierte Zeigerarithmetik erfordern, bietet ReadOnlySpan
2.4 Fehlende direkte Unterstützung in einigen APIs
Ähnlich wie beim zusammenhängenden Speicher ist es wichtig zu beachten, dass nicht alle APIs oder Bibliotheken möglicherweise nicht zusammenhängenden Speicher, der von ReadOnlySpan
Span und nicht verwalteter Speicher
In C# kann Span effektiv mit nicht verwaltetem Speicher verwendet werden, um speicherbezogene Operationen auf kontrollierte und effiziente Weise durchzuführen. Nicht verwalteter Speicher bezieht sich auf Speicher, der nicht vom Garbage Collector der .NET-Runtime verwaltet wird, und er beinhaltet oft die Verwendung von nativen Speicherallokationen und -freigaben. Hier ist, wie Span mit nicht verwaltetem Speicher in C# genutzt werden kann.
Zuweisung von nicht verwaltetem Speicher
Um nicht verwalteten Speicher zu allozieren, können Sie die Klasse System.Runtime.InteropServices.MemoryMarshal verwenden. Die Methode Marshal.AllocHGlobal allokiert Speicher und gibt einen Zeiger auf den allokierten Block zurück. Der allokierte Speicher oder die Speicheradresse wird in einem unmanagedMemory-Zeiger gehalten und hat Lese-/Schreibzugriff. Die zusammenhängenden Speicherbereiche können leicht zugegriffen werden.
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
Im obigen Quellcode allokieren wir einen Block nicht verwalteten Speichers mit Marshal.AllocHGlobal und erstellen dann einen Span<byte> mit dem Zeiger, der aus dem nicht verwalteten Speicher stammt. Damit können wir mit dem nicht verwalteten Speicher unter Verwendung der vertrauten Span-API arbeiten. Es ist wichtig zu beachten, dass bei der Arbeit mit nicht verwaltetem Speicher Sie selbst für das Management der Allokation und Freigabe des Speichers verantwortlich sind.
Kopieren von Daten in und aus nicht verwaltetem Speicher
Span bietet Methoden wie Slice, CopyTo und ToArray, die zum effizienten Kopieren von Daten zwischen verwaltetem und nicht verwaltetem Speicher verwendet werden können.
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
In diesem Beispiel:
Marshal.AllocHGlobalreserviert nicht verwalteten Speicher für die Zieldaten.new Span<int>(destinationPointer.ToPointer(), sourceArray.Length)erzeugt einSpan<int>aus dem zugewiesenen nicht verwalteten Speicher.- Die Methode
sourceSpan.CopyTo(destinationSpan)kopiert die Daten aus dem verwalteten Array in den nicht verwalteten Speicher. - Die Werte im Zielspeicher werden gedruckt, um die Kopieroperation zu überprüfen.
- Die Methode
Marshal.FreeHGlobal(destinationPointer)wird verwendet, um den nicht verwalteten Speicher nach Abschluss der Arbeiten freizugeben.
Verwendung von unsicherem Code
Beim Umgang mit nicht verwaltetem Speicher können Sie auch unsicheren Code mit Zeigern verwenden. In solchen Fällen können Sie mit der Methode Unsafe.AsPointer() einen Zeiger aus dem Span erhalten.
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
In diesem Beispiel verwenden wir die Unsafe.AsPointer-Methode, um einen Zeiger aus dem Span abzuleiten. Dies ermöglicht es uns, unsicheren Code zu verwenden, wenn direkt mit Zeigern gearbeitet wird.
Denken Sie daran, dass es bei der Arbeit mit nicht verwaltetem Speicher entscheidend ist, die Allokation und Freigabe ordnungsgemäß zu verwalten, um Speicherlecks zu vermeiden. Nicht verwalteter Speicher sollte stets mit geeigneten Methoden freigegeben werden, wie z. B. Marshal.FreeHGlobal(). Üben Sie außerdem Vorsicht beim Einsatz von unsicherem Code, da er potenzielle Sicherheitsrisiken mit sich bringen kann, wenn er nicht ordnungsgemäß gehandhabt wird.
Span und asynchrone Methodenaufrufe
Die Verwendung von Span in Verbindung mit asynchronen Methodenaufrufen in C# ist eine leistungsstarke Kombination, besonders beim Umgang mit großen Datenmengen oder I/O-Operationen. Das Ziel ist, asynchrone Operationen effizient und ohne unnötiges Kopieren von Daten zu behandeln. Lassen Sie uns erkunden, wie Sie Span in asynchronen Szenarien nutzen können:
1. Asynchrone E/A-Operationen:
Wenn Sie mit asynchronen I/O-Operationen umgehen, wie zum Beispiel beim Lesen oder Schreiben von Daten in einen Stream, können Sie 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
In diesem Beispiel liest die ReadAsync-Methode asynchron Daten von einem Stream in den Puffer. Die Methode ProcessData verarbeitet die Daten dann direkt aus dem Span
2. Asynchrone Dateioperationen:
Ähnlich wie bei I/O-Operationen können Sie bei asynchronen Dateioperationen Span nutzen, um die Daten effizient zu verarbeiten, ohne zusätzliches Kopieren.
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
Hier liest die ReadAsync-Methode Daten von einem Dateistream in den Puffer, und die ProcessData-Methode verarbeitet die Daten direkt aus dem Span
3. Asynchrone Aufgabenverarbeitung:
Wenn Sie mit asynchronen Aufgaben arbeiten, die Daten erzeugen oder konsumieren, können Sie 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
In diesem Beispiel verarbeitet die Methode ProcessDataAsync die Daten asynchron und gibt die Länge der verarbeiteten Daten zurück, ohne zusätzliche Kopien zu erstellen.
Einführung in IronPDF
IronPDF-Bibliotheksüberblick ist die neueste C#-PDF-Bibliothek von Iron Software, die verwendet werden kann, um auf dynamische Weise wunderschöne PDF-Dokumente in Echtzeit mit C#-Code zu generieren. IronPDF bietet eine Vielzahl von Funktionen wie PDF-Erstellung aus HTML, Umwandlung von HTML-Inhalten in PDF, Zusammenfügen oder Aufteilen von PDF-Dateien usw.
Die Hauptfunktion von IronPDF ist die HTML-zu-PDF-Funktionalität, die Layouts und Stile beibehält. Es kann PDFs aus Webinhalten generieren, was es großartig für Berichte, Rechnungen und Dokumentationen macht. Dieses Tool unterstützt die Umwandlung von HTML-Dateien, URLs und HTML-Strings in PDF-Dateien.
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 kann über den NuGet-Paketmanager für IronPDF-Konsole oder den Visual Studio-Paketmanager installiert werden.
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
In diesem Beispiel verwenden wir Span zusammen mit IronPDF, um ein PDF-Dokument zu erzeugen.
Ausgabe:

Erzeugtes PDF:

Lizenzierung (Kostenlose Testversion verfügbar)
IronPDF-Lizenzinformationen. Dieser Schlüssel muss in appsettings.json platziert werden.
"IronPdf.LicenseKey": "your license key"
Geben Sie Ihre E-Mail für eine Testlizenz an.
Abschluss
Span
Bitte besuchen Sie die IronPDF's Quick-Start-Dokumentationsseite.
Häufig gestellte Fragen
Was ist Span in C# und warum ist es wichtig?
Span
Wie optimiert Span die Speicherbearbeitung in C#?
Span
Was ist der Unterschied zwischen Span und ReadOnlySpan?
Span
Kann Span mit nicht verwaltetem Speicher in C# verwendet werden?
Ja, Span kann mit nicht verwaltetem Speicher verwendet werden, indem ein Span von einem Zeiger auf nicht verwalteten Speicher erstellt wird. Dies ermöglicht die direkte Manipulation des Speichers, während sichergestellt wird, dass er korrekt mit Methoden wie Marshal.AllocHGlobal und Marshal.FreeHGlobal zugewiesen und freigegeben wird.
Wie integriert sich IronPDF mit Span zur PDF-Generierung?
IronPDF kann zusammen mit Span
Was sind die Einschränkungen der Verwendung von Span für das Speichern-Management?
Die Einschränkungen von Span
Wie kann man IronPDF für die PDF-Manipulation in C# installieren?
IronPDF kann in einem C#-Projekt mithilfe des NuGet-Paketmanagers installiert werden. Verwenden Sie Befehle wie dotnet add package IronPDF oder Install-Package IronPDF, um es Ihrem Projekt hinzuzufügen.
Was sind die Vorteile der Verwendung von Span für die String-Manipulation?
Span
Gibt es eine Testversion von IronPDF?
Ja, IronPDF bietet eine Testlizenz, die erworben werden kann, indem Sie Ihre E-Mail angeben. Der Testlizenzschlüssel sollte in der appsettings.json-Datei platziert werden, um die Bibliothek zu verwenden.
Kann Span in asynchronen Methodenaufrufen verwendet werden?
Ja, Span kann in asynchronen Methodenaufrufen verwendet werden, um Daten effizient zu verarbeiten, ohne unnötige Kopien zu erstellen. Dies ist besonders nützlich bei I/O-Operationen und der Dateiverarbeitung, wobei Memory oder Span ausgenutzt werden.




