Zum Fußzeileninhalt springen
.NET HILFE

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

ReadOnlySpan

Während Span<T> veränderlich ist und Modifikationen der zugrunde liegenden Daten ermöglicht, ist ReadOnlySpan<T> eine unveränderliche Ansicht des Speichers. Es bietet eine schreibgeschützte Schnittstelle zu einem zusammenhängenden Speicherbereich, was es für Szenarien geeignet macht, in denen Sie nur die Daten lesen möchten, ohne sie zu ändern.

Hier sind einige wichtige Punkte.

1. Nur-Lese-Ansicht

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

2. die Darstellung des Speichers

Wie Span<T> besitzt ReadOnlySpan<T> nicht den Speicher, auf den es zeigt. Es verweist auf existierenden Speicher und kann auf Arrays, Stack-allokierten Speicher oder nativen Speicher zeigen.

3. leistungsbezogene Vorteile

Wie Span<T> kann ReadOnlySpan<T> im Vergleich zu traditionellen Sammlungstypen eine bessere Leistung bieten, insbesondere beim Umgang mit großen Datenmengen, da es die Notwendigkeit zum Kopieren reduziert.

4. keine Prüfung von Grenzen

Wie bei Span<T> führt ReadOnlySpan<T> keine Bereichsüberprüfungen durch. Es ist die Verantwortung des Entwicklers, sicherzustellen, dass die Operationen innerhalb der Grenzen des zugrunde liegenden Speichers bleiben.

5. Verwendung mit Array Slicing

ReadOnlySpan<T> unterstützt das Slicing, sodass Sie Teilbereiche erstellen können, die auf einen Teil des ursprünglichen Speichers verweisen.

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

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

3. die Übergabe einer Zeichenkette an eine Methode

Übergeben Sie ReadOnlySpan als Parameter an die Methode.

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

4. Suche innerhalb einer Zeichenkette

ReadOnlySpan für die Suche innerhalb eines Strings mit IndexOf().

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

5. Verwendung von Memory-Mapped-Dateien

ReadOnlySpan kann bei speicherabbildeten Dateien effizienter sein.

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

6. effiziente String-Manipulation

ReadOnlySpan kann für eine effiziente String-Manipulation genutzt werden.

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

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

ReadOnlySpan bietet eine Möglichkeit, effizient mit Strings zu arbeiten, insbesondere in Szenarien, in denen Speicherallokationen und Kopieren minimiert werden sollten. Es ist ein leistungsstarkes Werkzeug zur Optimierung von performance-kritischem Code und kann besonders vorteilhaft sein, wenn es um große Mengen an String-Daten geht.

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<T> zu undefiniertem Verhalten oder potenziellen Abstürzen führen kann. Entwickler müssen sicherstellen, dass der zugrunde liegende Speicher weiterhin gültig ist, wenn sie ein Span<T> verwenden.

1.2 Keine Garbage Collection

Da Span<T> keinen Speicher besitzt, unterliegt es nicht der Garbage Collection. Daher müssen Sie vorsichtig sein, wenn Sie mit auf dem Stack allokiertem Speicher oder Speicher arbeiten, der eine kürzere Lebensdauer als das Span<T> selbst hat.

1.3 Überprüfung der Grenzen ist deaktiviert

Span<T> und ReadOnlySpan<T> führen standardmäßig keine Bereichsüberprüfungen durch. Dies kann dazu führen, dass auf ungültige Speicherorte zugegriffen wird, wenn es nicht sorgfältig verwendet wird. Entwickler müssen manuell sicherstellen, dass die Operationen auf einem Span<T> innerhalb der Grenzen des zugrunde liegenden Speichers bleiben.

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

Span<T> ist so konzipiert, dass es mit zusammenhängendem Speicher arbeitet. Wenn Sie nicht zusammenhängenden Speicher haben oder komplexere Datenstrukturen darstellen müssen, ist Span<T> möglicherweise nicht die angemessenste Wahl.

1.5 Nicht alle Operationen werden unterstützt

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

1.6 Eingeschränkte Plattformkompatibilität

Obwohl Span<T> Teil des .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 Span<T> unterstützt, wenn Sie planen, es in Ihrem Code zu verwenden.

2. nicht-zusammenhängende Speicherpuffer

2.1 Begrenzte Unterstützung für nicht zusammenhängenden Speicher

ReadOnlySpan<T> ist hauptsächlich so konzipiert, dass es nahtlos mit zusammenhängenden Speicherblöcken oder Puffern arbeitet. Es ist möglicherweise nicht die am besten geeignete Wahl für Szenarien, in denen nicht zusammenhängende Speicherpuffer oder Strukturen mit Lücken im Speicher beteiligt sind.

2.2 Strukturelle Beschränkungen

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

2.3 Komplexe Zeigeroperationen

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

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<T> dargestellt wird, direkt unterstützen. Die Anpassung an solche Szenarien kann zusätzliche Zwischenschritte oder Konvertierungen erfordern, um die Kompatibilität sicherzustellen.

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

Im obigen Quellcode allozieren wir einen Block des nicht verwalteten Speichers mit Marshal.AllocHGlobal und erstellen dann einen Span<byte> mit dem aus dem nicht verwalteten Speicher erhaltenen Zeiger. 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 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 = 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
$vbLabelText   $csharpLabel

In diesem Beispiel:

  • Marshal.AllocHGlobal allokiert nicht verwalteten Speicher für die Zieldaten.
  • new Span<int>(destinationPointer.ToPointer(), sourceArray.Length) erstellt einen Span<int> aus dem allokierten nicht verwalteten Speicher.
  • Die Methode sourceSpan.CopyTo(destinationSpan) kopiert die Daten vom 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 Arbeit frei zu geben.

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

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. Geben Sie immer nicht verwalteten Speicher mit den entsprechenden Methoden wie Marshal.FreeHGlobal() frei. Ü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<T> oder Span<T> verwenden, um effizient mit den Daten zu arbeiten, ohne zusätzliche Puffer zu erstellen.

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

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, ohne sie in einen anderen Puffer zu kopieren.

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

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<T> oder Span<T> verwenden, um unnötige Kopien zu vermeiden.

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

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

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

C# Span (Wie es für Entwickler funktioniert): Abbildung 1 - Installieren Sie IronPDF mithilfe des NuGet-Paketmanagers, indem Sie IronPDF in die Suchleiste des NuGet-Paketmanagers eingeben

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

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

Output:

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"

Geben Sie Ihre E-Mail für eine Testlizenz an.

Abschluss

Span<T> in C# bietet eine leistungsstarke und effiziente Möglichkeit, mit Speicher zu arbeiten und bringt Vorteile in Bezug auf Leistung und Flexibilität. Seine nicht-besitzende, zusammenhängende Natur macht es besonders geeignet für Szenarien, in denen die Minimierung von Speicherallokationen und das Kopieren entscheidend sind. Durch die Nutzung von Span können Entwickler eine bessere Leistung in einer Vielzahl von Anwendungen erreichen, von der String-Manipulation bis zur Hochleistungs-Numerikverarbeitung. Durch das Verständnis seiner Funktionen und die Berücksichtigung seiner Einschränkungen können Entwickler Span<T> sicher und effizient für verschiedene Aufgaben zur Speicherbearbeitung nutzen. Zusammen mit IronPDF-Bibliotheksüberblick kann es verwendet werden, um großartige PDF-Dokumente ohne await und yield-Grenzen zu erzeugen.

Bitte besuchen Sie die IronPDF's Quick-Start-Dokumentationsseite.

Häufig gestellte Fragen

Was ist Span in C# und warum ist es wichtig?

Span<T> ist ein in C# 7.2 eingeführter Typ, der einen zusammenhängenden Speicherbereich darstellt. Er ist wichtig, da er es Entwicklern ermöglicht, effiziente Low-Level-Speicheroperationen ohne die Overhead von Heap-Allocations durchzuführen und die Sicherheit und Leistung von C# aufrechtzuerhalten.

Wie optimiert Span<T> die Speicherbearbeitung in C#?

Span<T> optimiert die Speicherbearbeitung, indem es eine Zero-Copy-Abstraktion über den Speicher bereitstellt, die es Entwicklern ermöglicht, bestehende Speicherblöcke zu referenzieren, ohne Daten zu duplizieren. Dies führt zu Leistungsverbesserungen, insbesondere in Anwendungen, die große Datenmengen verarbeiten.

Was ist der Unterschied zwischen Span<T> und ReadOnlySpan<T>?

Span<T> ist eine veränderbare Sicht auf den Speicher, die Modifikationen zulässt, während ReadOnlySpan<T> eine schreibgeschützte Sicht bietet. ReadOnlySpan<T> wird verwendet, wenn Daten nicht modifiziert werden sollen, bietet ähnliche Leistungsgewinne und gewährleistet gleichzeitig die Datenintegrität.

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<T> zur PDF-Generierung?

IronPDF kann zusammen mit Span<T> arbeiten, um PDFs dynamisch zu generieren, indem es den Speicher effizient verwaltet und unnötige Allokationen vermeidet. Diese Integration ermöglicht es Entwicklern, PDF-Dokumente aus Webinhalten mit verbesserter Leistung zu erstellen.

Was sind die Einschränkungen der Verwendung von Span<T> für das Speichern-Management?

Die Einschränkungen von Span<T> umfassen das Erfordernis für zusammenhängenden Speicher, das Fehlen automatischer Speicherverwaltung und Garbage Collection sowie keine Unterstützung für nicht zusammenhängenden Speicher. Entwickler müssen manuell die Speichergültigkeit und -grenzen sicherstellen.

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<T> für die String-Manipulation?

Span<T> ermöglicht eine effiziente String-Manipulation, indem Speicherallokationen und Kopieren minimiert werden. Dies ist besonders vorteilhaft in leistungskritischem Code, in dem große Mengen von String-Daten verarbeitet werden.

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<T> 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.

Jacob Mellor, Chief Technology Officer @ Team Iron
Chief Technology Officer

Jacob Mellor ist Chief Technology Officer bei Iron Software und ein visionärer Ingenieur, der führend in der C# PDF-Technologie ist. Als ursprünglicher Entwickler der Iron Software-Kerncodebasis hat er die Produktarchitektur des Unternehmens seit seiner Gründung gestaltet und zusammen mit CEO Cameron Rimington in ein Unternehmen ...

Weiterlesen