.NET-HILFE

C# Span (Wie es für Entwickler funktioniert)

Chipego
Chipego Kalinda
6. März 2024
Teilen Sie:

Span ist ein Typ, der in C# 7.2 als Teil der Span-Struktur im System-Namespace eingeführt wurde. Er ist so konzipiert, dass er einen zusammenhängenden Bereich eines beliebigen Speichers darstellt. Im Gegensatz zu Arrays oder Sammlungen wie dem verwalteten Heap besitzt Span nicht den Stapelspeicher oder den Speicherbereich, auf den es zeigt; stattdessen bietet es eine leichtgewichtige Sicht auf vorhandene Speicherblöcke. Diese Eigenschaft macht Span besonders leistungsfähig für Szenarien, in denen Sie effizient mit Speicherpuffern arbeiten müssen, ohne zusätzlichen Overhead und unsichere Codeszenarien zu verursachen. Später in diesem Artikel werden wir auch die Einführung in die IronPDF-Bibliothek von Iron Software sehen.

Hauptmerkmale der Spanne

1. Speicherverwaltung

Span in C# ermöglicht es Entwicklern, direkt mit Speicher zu arbeiten, ohne auf traditionelle Heap-Zuweisungen zurückgreifen zu müssen. Es bietet eine Möglichkeit, Speicherabschnitte aus bestehenden Arrays oder anderen Speicherquellen zu erstellen, wodurch zusätzliche Speicherkopien überflüssig werden.

2. Null-Kopie-Abstraktionen

Eines der herausragenden Merkmale von C# Span sind seine Null-Kopie-Abstraktionen. Anstatt Daten zu duplizieren, bietet Span eine Möglichkeit, effizient auf vorhandenen Speicher zu verweisen. Dies ist besonders vorteilhaft für Szenarien, in denen das Kopieren großer Datenmengen unpraktisch oder zu kostspielig wäre.

3. Zeiger-ähnliche Operationen

Während C# traditionell eine sichere High-Level-Sprache ist, führt Span ein gewisses Maß an Low-Level-Speichermanipulation ein, das der Arbeit mit Zeigern in Sprachen wie C oder C++ ähnelt. Entwickler können zeigerähnliche Operationen durchführen, ohne auf die Sicherheit und den verwalteten Charakter von C# zu verzichten.

4. Unveränderliche Natur

Trotz seiner Möglichkeiten für den Speicherzugriff auf niedriger Ebene bleibt C# Span unveränderlich. Das bedeutet, dass es zwar die Manipulation des Speichers erlaubt, aber gleichzeitig die Sicherheit erhöht, indem es unbeabsichtigte Änderungen verhindert.

Beispiel

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
$vbLabelText   $csharpLabel

ReadOnlySpan

Während Span<T> veränderlich ist und Modifikationen an den zugrunde liegenden Daten erlaubt, ist ReadOnlySpan<T> eine unveränderliche Ansicht des Speichers. Sie bietet eine Nur-Lese-Schnittstelle zu einem zusammenhängenden Speicherbereich und eignet sich daher für Szenarien, in denen Sie die Daten nur lesen, aber nicht verändern müssen.

Hier sind einige wichtige Punkte.

1. Schreibgeschützte Ansicht

Wie der Name schon sagt, ermöglicht ReadOnlySpanIhnen, eine schreibgeschützte Ansicht eines Speicherblocks zu erstellen. Dies bedeutet, dass Sie die Elemente nicht über einen ReadOnlySpan<T> ändern können.

2. Darstellung des Speichers

Wie Spanbesitzt ReadOnlySpannicht den Speicher, auf den es verweist. Er bezieht sich auf vorhandenen Speicher und kann auf Arrays, Stack-allocated Memory oder Native Memory verweisen.

3. Leistungsvorteile

Wie Span<T> kann ReadOnlySpan<T> eine bessere Leistung im Vergleich zu traditionellen Sammlungstypen bieten, insbesondere bei der Verarbeitung großer Datenmengen, da es den Bedarf an Kopieren reduziert.

4. Prüfung ohne Grenzen

Wie bei Spanführt ReadOnlySpankeine Bereichsüberprüfung durch. Es liegt in der Verantwortung des Entwicklers, sicherzustellen, dass die Operationen innerhalb der Grenzen des zugrunde liegenden Speichers bleiben.

5. Verwendung mit Array Slicing

ReadOnlySpanunterstützt das Slicing, sodass Sie Teilbereiche erstellen können, die einen Abschnitt des ursprünglichen Speichers referenzieren.

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
$vbLabelText   $csharpLabel

Es gibt viele verschiedene Möglichkeiten, ReadOnlySpan zu erstellen und mit ihm zu arbeiten. Nachstehend 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
$vbLabelText   $csharpLabel

2. Arbeiten mit Teilstrings

Verwenden Sie Slice auf dem ReadOnlySpan<char>

ReadOnlySpan<char> substringSpan = spanFromString.Slice(startIndex, length);
ReadOnlySpan<char> substringSpan = spanFromString.Slice(startIndex, length);
Dim substringSpan As ReadOnlySpan(Of Char) = spanFromString.Slice(startIndex, length)
$vbLabelText   $csharpLabel

3. Übergabe von Substraten an eine Methode

Übergeben Sie ReadOnlySpan<char> als Parameter an die Methode.

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))
$vbLabelText   $csharpLabel

4. Suche innerhalb einer Zeichenkette

ReadOnlySpanfür die Suche innerhalb einer Zeichenfolge mit IndexOf().

int index = stringSpan.IndexOf('W');
int index = stringSpan.IndexOf('W');
Dim index As Integer = stringSpan.IndexOf("W"c)
$vbLabelText   $csharpLabel

5. Verwendung von Memory-Mapped-Dateien

ReadOnlySpankann bei speicherabbildeten Dateien effizienter sein.

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
$vbLabelText   $csharpLabel

6. Effiziente Manipulation von Zeichenketten

ReadOnlySpankann für eine effiziente Zeichenfolgenmanipulation verwendet werden.

// 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)
$vbLabelText   $csharpLabel

7. Übergabe von Substraten an APIs

Bei der Arbeit mit externen Bibliotheken oder APIs, die mit Zeichenabständen arbeiten.

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))
$vbLabelText   $csharpLabel

ReadOnlySpanbietet eine Möglichkeit, effizienter mit Zeichenfolgen zu arbeiten, insbesondere in Szenarien, bei denen Speicherzuweisungen und -kopien minimiert werden sollten. Es ist ein leistungsfähiges Werkzeug zur Optimierung von leistungskritischem Code und kann besonders bei großen Mengen an Zeichenkettendaten von Vorteil sein.

Spannenbegrenzungen

Obwohl Span in C# eine leistungsstarke Funktion mit zahlreichen Vorteilen ist, gibt es auch einige Einschränkungen und Überlegungen, insbesondere im Zusammenhang mit zusammenhängendem und nicht zusammenhängendem Speicher. Lassen Sie uns diese Einschränkungen untersuchen:

1. Zusammenhängende Speicherpuffer

1.1 Keine automatische Speicherverwaltung

Spanverwaltet den Speicher, auf den es zeigt, nicht. Das bedeutet, dass die Verwendung von Span<T> zu undefiniertem Verhalten oder potenziellen Abstürzen führen kann, wenn der zugrunde liegende verwaltete Speicher freigegeben wird oder aus dem Gültigkeitsbereich fällt. Entwickler müssen sicherstellen, dass der zugrundeliegende Speicher noch gültig ist, wenn ein Span<T> verwendet wird.

1.2 Keine Müllabfuhr

Da Span<T> keinen Speicher besitzt, unterliegt es nicht der Speicherbereinigung. Daher muss man vorsichtig sein, wenn man mit speicherplatzallokiertem Speicher oder Speicher mit einer kürzeren Lebensdauer als der Span<T> selbst arbeitet.

1.3 Bounds Checking ist deaktiviert

Spanund ReadOnlySpanführen standardmäßig keine Bereichsüberprüfung durch. Dies kann dazu führen, dass auf ungültige Speicherplätze zugegriffen wird, wenn nicht sorgfältig damit umgegangen wird. Entwickler müssen manuell sicherstellen, dass die Operationen auf einem Spaninnerhalb der Grenzen des zugrunde liegenden Speichers bleiben.

1.4 Keine Unterstützung für nicht zusammenhängenden Speicher

Span<T> ist dafür ausgelegt, mit zusammenhängendem Speicher zu arbeiten. Wenn Sie über nicht zusammenhängenden Speicher verfügen oder komplexere Datenstrukturen darstellen müssen, ist Spanmöglicherweise nicht die geeignetste Wahl.

1.5 Es werden nicht alle Operationen unterstützt

Während Span<T> viele gängige Operationen wie Schneiden, Indexierung und Iteration unterstützt, werden nicht alle Operationen unterstützt. Zum Beispiel können Sie ein Spannicht ändern, und bestimmte Operationen, die eine Änderung der Länge des zugrunde liegenden Speichers beinhalten, sind nicht erlaubt.

1.6 Eingeschränkte Plattformkompatibilität

Während Span<T> Teil von .NET Standard und .NET Core ist, ist es möglicherweise nicht auf allen Plattformen oder Umgebungen verfügbar. Es ist entscheidend, sicherzustellen, dass Ihre Zielplattform Spanunterstützt, wenn Sie planen, es in Ihrem Code zu verwenden.

2. Nicht zusammenhängende Speicherpuffer

2.1 Eingeschränkte Unterstützung für nicht zusammenhängenden Speicher

ReadOnlySpanist in erster Linie dafür konzipiert, nahtlos mit zusammenhängenden Speicherblöcken oder Puffern zu arbeiten. Es ist möglicherweise nicht die beste Wahl für Szenarien, in denen nicht zusammenhängende Speicherpuffer oder Strukturen mit Lücken im Speicher betroffen sind.

2.2 Strukturelle Beschränkungen

Bestimmte Datenstrukturen oder Szenarien, die auf nicht zusammenhängendem Speicher basieren, passen möglicherweise nicht gut zu ReadOnlySpan<T>. Zum Beispiel könnten Datenstrukturen wie verkettete Listen oder Graphstrukturen aufgrund des zusammenhängenden Speicherbedarfs von ReadOnlySpan<T> nicht gut geeignet sein.

2.3 Komplexe Zeigeroperationen

In Situationen, die nicht zusammenhängenden Speicher betreffen, insbesondere solche, die komplizierte Zeigerarithmetik erfordern, bietet ReadOnlySpan<T> möglicherweise nicht die gleiche Kontrolle und Flexibilität auf niedriger Ebene wie rohe Zeiger in Sprachen wie C++. In solchen Fällen könnte die Verwendung von unsicherem Code mit Zeigern sinnvoller sein.

2.4 Fehlende direkte Unterstützung in einigen APIs

Ähnlich wie zusammenhängender Speicher ist es wichtig zu beachten, dass nicht alle APIs oder Bibliotheken möglicherweise direkt nicht-zusammenhängenden Speicher unterstützen, der durch ReadOnlySpanrepräsentiert wird. Die Anpassung an solche Szenarien kann zusätzliche Zwischenschritte oder Konvertierungen erforderlich machen, um die Kompatibilität zu gewährleisten.

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. Unverwalteter Speicher bezieht sich auf Speicher, der nicht vom Garbage Collector der .NET-Laufzeitumgebung verwaltet wird, und beinhaltet oft die Verwendung von nativen Speicherzuweisungen und -freigaben. Hier ist, wie Span kann mit unmanaged Speicher in C# verwendet werden.

Zuweisung von nicht verwaltetem Speicher

Um nicht verwalteten Speicher zuzuweisen, können Sie die Klasse System.Runtime.InteropServices.MemoryMarshal verwenden. Die Marshal.AllocHGlobal-Methode weist Speicher zu und gibt einen Zeiger auf den zugewiesenen Block zurück. Der zugewiesene Speicher oder die Speicheradresse wird in einem unmanagedMemory-Zeiger gehalten und hat Lese- und Schreibzugriff. Auf die zusammenhängenden Bereiche des Speichers kann 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
$vbLabelText   $csharpLabel

Im obigen Quellcode allokieren wir einen Block von nicht verwaltetem Speicher mithilfe von Marshal.AllocHGlobal und erstellen dann ein Spanunter Verwendung des Zeigers, der aus dem nicht verwalteten Speicher erhalten wurde. Dadurch können wir mit nicht verwaltetem Speicher arbeiten, indem wir die bekannte Span-API verwenden. Es ist wichtig zu wissen, dass Sie bei der Arbeit mit nicht verwaltetem Speicher für die Verwaltung der Zuweisung und Freigabe des Speichers verantwortlich sind.

Kopieren von Daten in und aus nicht verwaltetem Speicher

Span bietet Methoden wie Slice, CopyTo und ToArray, die für das effiziente 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 = 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
$vbLabelText   $csharpLabel

In diesem Beispiel:

MemoryMarshal.Allocate(sourceArray.Length) reserviert nicht verwalteten Speicher für die Zieldaten. MemoryMarshal.Cast<int, byte>(destinationPointer, sourceArray.Length) erstellt einen Spanaus 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 ausgedruckt, um den Kopiervorgang zu überprüfen. Die Methode MemoryMarshal.Free(destinationPointer) wird verwendet, um den nicht verwalteten Speicher nach der Verwendung freizugeben.

Unsicheren Code verwenden

Wenn Sie mit nicht verwaltetem Speicher arbeiten, können Sie auch unsicheren Code mit Zeigern verwenden. In solchen Fällen können Sie einen Zeiger aus dem Span mit der Unsafe.AsPointer()-Methode erhalten.

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
$vbLabelText   $csharpLabel

In diesem Beispiel verwenden wir die Methode Unsafe.AsPointer, um einen Zeiger von Span zu erhalten. Dies ermöglicht uns die Verwendung von unsicherem Code, wenn wir direkt mit Zeigern arbeiten.

Denken Sie daran, dass es bei der Arbeit mit nicht verwaltetem Speicher wichtig ist, die Zuweisung und Freigabe richtig zu verwalten, um Speicherlecks zu vermeiden. Verwenden Sie immer geeignete Methoden, wie beispielsweise Marshal.FreeHGlobal(), um nicht verwalteten Speicher freizugeben. Seien Sie außerdem vorsichtig bei der Verwendung von unsicherem Code, da dieser bei unsachgemäßer Handhabung potenzielle Sicherheitsrisiken bergen kann.

Span und asynchrone Methodenaufrufe

Die Verwendung von Span in Verbindung mit asynchronen Methodenaufrufen in C# ist eine leistungsstarke Kombination, vor allem wenn es um große Datenmengen oder E/A-Operationen geht. Ziel ist es, asynchrone Operationen ohne unnötiges Kopieren von Daten effizient abzuwickeln. Lassen Sie uns untersuchen, wie Sie Span in asynchronen Szenarien nutzen können:

Asynchrone I/O-Operationen:

Beim Umgang mit asynchronen I/O-Operationen, wie dem Lesen oder Schreiben von Daten in einen Stream, können Sie Memory<T> oder Span<T> verwenden, um effizient mit den Daten zu arbeiten, ohne zusätzliche Puffer zu erstellen.

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
$vbLabelText   $csharpLabel

In diesem Beispiel liest die Methode ReadAsync asynchron Daten aus einem Stream in den Puffer. Die Methode ProcessData verarbeitet die Daten dann direkt aus dem Span, ohne sie in einen anderen Puffer zu kopieren.

2. Asynchrone Dateioperationen:

Ähnlich wie bei E/A-Operationen können Sie bei asynchronen Dateioperationen Span verwenden, um Daten ohne zusätzliches Kopieren effizient zu verarbeiten.

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
$vbLabelText   $csharpLabel

Hier liest die Methode ReadAsync Daten aus einem Dateistream in den Puffer, und die Methode ProcessData verarbeitet die Daten direkt aus dem Span.

3. Asynchrone Aufgabenverarbeitung:

Wenn Sie mit asynchronen Aufgaben arbeiten, die Daten produzieren oder konsumieren, können Sie Memory<T> oder Span<T> verwenden, um unnötige Kopien zu vermeiden.

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
$vbLabelText   $csharpLabel

In diesem Beispiel verarbeitet die Methode ProcessDataAsync die Daten asynchron und gibt die Länge der verarbeiteten Daten zurück, ohne dass zusätzliche Kopien erforderlich sind.

Einführung in IronPDF

IronPDF-Bibliothek Übersicht ist die neueste C#-PDF-Bibliothek von Iron Software, die verwendet werden kann, um mit C#-Code dynamisch wunderschöne PDF-Dokumente zu erstellen. IronPDF bietet eine Vielzahl von Funktionen, wie z. B. PDF-Erzeugung aus HTML, Konvertierung von HTML-Inhalten in PDF, Zusammenführen oder Teilen von PDF-Dateien usw.

Die Hauptfunktion von IronPDF ist seine HTML-zu-PDF-Funktionalität, die Layouts und Stile bewahrt. Es kann PDFs aus Webinhalten generieren und eignet sich daher hervorragend für Berichte, Rechnungen und Dokumentationen. 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
$vbLabelText   $csharpLabel

Einrichtung

IronPDF kann über den NuGet-Paketmanager für IronPDF Konsole oder über den Visual Studio-Paketmanager installiert werden.

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
$vbLabelText   $csharpLabel

C# Span (Wie es für Entwickler funktioniert): Abbildung 1 - Installieren Sie IronPDF mit dem NuGet-Paket-Manager, indem Sie im Suchfeld des NuGet-Paket-Managers nach ironpdf suchen

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
$vbLabelText   $csharpLabel

In diesem Beispiel verwenden wir Span zusammen mit IronPDF, um ein PDF-Dokument zu erstellen.

Ausgabe:

C# Span (Wie es für Entwickler funktioniert): Abbildung 2 - Konsolenausgabe

Erzeugtes PDF:

C# Span (Wie es für Entwickler funktioniert): Abbildung 3 - PDF-Ausgabe

Lizenzierung (kostenlose Testversion verfügbar)

IronPDF-Lizenzinformationen. Dieser Schlüssel muss in appsettings.json platziert werden.

"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"
$vbLabelText   $csharpLabel

Geben Sie Ihre E-Mail-Adresse an, um eine Testlizenz zu erhalten.

Schlussfolgerung

Span<T> in C# bietet eine leistungsstarke und effiziente Möglichkeit, mit Speicher zu arbeiten und bietet Vorteile in Bezug auf Leistung und Flexibilität. Die nicht-besitzende, zusammenhängende Natur macht es besonders geeignet für Szenarien, in denen die Minimierung von Speicherzuweisungen und -kopien entscheidend ist. Durch den Einsatz von Span können Entwickler eine bessere Leistung in einer Vielzahl von Anwendungen erzielen, die von der Zeichenkettenmanipulation bis zur leistungsstarken numerischen Verarbeitung reichen. Indem Entwickler die Funktionen von Span<T> verstehen und seine Einschränkungen berücksichtigen, können sie es sicher und effizient für verschiedene Aufgaben der Speicherverwaltung einsetzen. Zusammen mit der IronPDF-Bibliotheksübersicht kann es verwendet werden, um beeindruckende PDF-Dokumente ohne await- und yield-Grenzen zu erstellen.

Bitte besuchen Sie die Schnellstart-Dokumentationsseite von IronPDF.

Chipego
Software-Ingenieur
Chipego hat eine natürliche Fähigkeit zum Zuhören, die ihm hilft, Kundenprobleme zu verstehen und intelligente Lösungen anzubieten. Er trat dem Iron Software-Team 2023 bei, nachdem er einen Bachelor of Science in Informationstechnologie erworben hatte. IronPDF und IronOCR sind die beiden Produkte, auf die sich Chipego konzentriert hat, aber sein Wissen über alle Produkte wächst täglich, da er neue Wege findet, Kunden zu unterstützen. Er genießt die Zusammenarbeit bei Iron Software, da Teammitglieder aus dem gesamten Unternehmen ihre unterschiedlichen Erfahrungen einbringen und so zu effektiven, innovativen Lösungen beitragen. Wenn Chipego nicht an seinem Schreibtisch sitzt, kann man ihn oft bei einem guten Buch oder beim Fußballspielen antreffen.
< PREVIOUS
C# IDE (Wie es für Entwickler funktioniert)
NÄCHSTES >
Opentelemetry C# (Wie es für Entwickler funktioniert)