.NET 幫助

C# Span(開發者如何使用)

發佈 2024年3月6日
分享:

跨度 是在 C# 7.2 中作為 Span 的一部分引入的一種類型System 命名空間中的 struct。 它被設計用來表示任意內存的連續區域。 與受控堆等數組或集合不同,Span 不擁有其指向的堆棧記憶體或記憶體區域; 相反,它提供了對現有記憶體區塊的輕量級視圖。 這一特性使 Span 尤其強大,特別適用於需要高效處理記憶體緩衝區而不產生額外負擔和不安全代碼情形的場景。 稍後在本文中,我們還將看到介紹到IronPDF 函式庫Iron Software.

Span的主要特徵

1. 記憶體管理

C# 中的 Span 允許開發人員直接處理記憶體,而不需要使用傳統的堆分配。 它提供了一種從現有數組或其他內存來源創建內存切片的方法,消除了額外內存拷貝的需要。

2. 零拷貝抽象

C# Span 的一個突出特點是其零拷貝抽象。 Span 提供了一種有效引用現有記憶體的方法,而不是重複資料。 這在需要複製大量資料但實際上不切實際或成本太高的情況下特別有利。

3. 指標類操作

雖然 C# 傳統上是一種高層次且安全的語言,但 Span 引入了類似於使用 C 或 C++ 等語言中的指標進行低層次記憶體操作的程度。 開發人員可以在不犧牲 C# 的安全性和管理特性的情況下執行類似指針的操作。

4. 不可變性質

儘管 C# Span 具有低層級記憶體存取的功能,但仍然是不可變的。 這意味著,在允許操作記憶體的同時,它通過防止無意的修改來強化安全性。

範例

using System;
class Program
{
    void Main()
    {
        int[] array = { 1, 2, 3, 4, 5 };
        // Create a span that points to the entire array
        Span<int> span = array;
        // Modify the data using the span
        span[2] = 10;
        // Print the modified array
        foreach (var item in array)
        {
            Console.WriteLine(item);
        }
    }
}
using System;
class Program
{
    void Main()
    {
        int[] array = { 1, 2, 3, 4, 5 };
        // Create a span that points to the entire array
        Span<int> span = array;
        // Modify the data using the span
        span[2] = 10;
        // Print the modified array
        foreach (var item in array)
        {
            Console.WriteLine(item);
        }
    }
}
Imports System
Friend Class Program
	Private Sub Main()
		Dim array() As Integer = { 1, 2, 3, 4, 5 }
		' Create a span that points to the entire array
		Dim span As Span(Of Integer) = array
		' Modify the data using the span
		span(2) = 10
		' Print the modified array
		For Each item In array
			Console.WriteLine(item)
		Next item
	End Sub
End Class
VB   C#

唯讀範圍

當範圍是可變的並允許對基礎數據進行修改,ReadOnlySpan是記憶體的不可變視圖。 它提供了一個唯讀介面給一個連續的記憶體區域,適合於只需要讀取資料而不進行修改的情境。

以下是一些要點。

唯讀檢視

顧名思義,ReadOnlySpan允許您創建記憶體區塊的唯讀視圖。 這意味著你不能通過 ReadOnlySpan 修改元素。.

2. 記憶體表示

喜歡跨度,ReadOnlySpan不擁有它指向的記憶體。 它指的是現有的記憶體,並且可以指向陣列、堆疊分配的記憶體或本機記憶體。

3. 性能優勢

喜歡跨度,ReadOnlySpan可以提供比傳統集合類型更好的性能,特別是在處理大量數據時,因為它減少了複製的需求。

4. 無邊界檢查

如同 Span,ReadOnlySpan不執行邊界檢查。 開發人員有責任確保操作保持在基礎記憶體的範圍內。

5. 與陣列切片的使用

唯讀範圍支援切片功能,允許您創建引用原始記憶體部分的子片段。

範例

using System;
class Program
{
    static void Main()
    {
        int[] array = { 1, 2, 3, 4, 5 };
        // Create a read-only span that points to the entire array
        ReadOnlySpan<int> readOnlySpan = array;
        // Access and print the data through the read-only span
        foreach (var item in readOnlySpan)
        {
            Console.WriteLine(item);
        }
        // Note: The following line would result in a compilation error since readOnlySpan is read-only.
        // readOnlySpan[2] = 10;
    }
}
using System;
class Program
{
    static void Main()
    {
        int[] array = { 1, 2, 3, 4, 5 };
        // Create a read-only span that points to the entire array
        ReadOnlySpan<int> readOnlySpan = array;
        // Access and print the data through the read-only span
        foreach (var item in readOnlySpan)
        {
            Console.WriteLine(item);
        }
        // Note: The following line would result in a compilation error since readOnlySpan is read-only.
        // readOnlySpan[2] = 10;
    }
}
Imports System
Friend Class Program
	Shared Sub Main()
		Dim array() As Integer = { 1, 2, 3, 4, 5 }
		' Create a read-only span that points to the entire array
		Dim readOnlySpan As ReadOnlySpan(Of Integer) = array
		' Access and print the data through the read-only span
		For Each item In readOnlySpan
			Console.WriteLine(item)
		Next item
		' Note: The following line would result in a compilation error since readOnlySpan is read-only.
		' readOnlySpan[2] = 10;
	End Sub
End Class
VB   C#

有許多不同的方法可以創建 ReadOnlySpan 並使用它。 以下是一些示例。

1. 從字串建立 ReadOnlySpan

string msg = "Hello, World!";
ReadOnlySpan<char> span1 = msg.AsSpan();
// Read-only manipulation
char firstChar = span1[0];
Console.WriteLine(firstChar); // Outputs: H
string msg = "Hello, World!";
ReadOnlySpan<char> span1 = msg.AsSpan();
// Read-only manipulation
char firstChar = span1[0];
Console.WriteLine(firstChar); // Outputs: H
Dim msg As String = "Hello, World!"
Dim span1 As ReadOnlySpan(Of Char) = msg.AsSpan()
' Read-only manipulation
Dim firstChar As Char = span1(0)
Console.WriteLine(firstChar) ' Outputs: H
VB   C#

2. 使用子字串

在 ReadOnlySpan 上使用 Slice

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

3. 傳遞子字串到方法

傳遞 ReadOnlySpan作為方法的參數。

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

4. 字串內搜尋

唯讀範圍在字串中使用 IndexOf 搜尋().

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

5. 使用記憶體映射檔案

唯讀範圍使用記憶體對映文件可以更有效率。

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

6. 高效字串操作

唯讀範圍可用於高效的字串操作。

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

7. 傳遞子字串到 APIs

使用外部庫或操作字元範圍的 API 時。

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

唯讀範圍提供了一種更有效地處理字串的方法,特別是在需要最小化記憶體分配和複製的情境中。 這是一個強大的工具,可以優化性能關鍵代碼,在處理大量字串數據時特別有益。

範圍限制

雖然 C# 中的 Span 是一個強大的功能,具有許多優勢,但在連續和非連續記憶體的情境下,確實存在某些限制和考量。 讓我們來探索這些限制:

連續記憶體緩衝區

1.1 無自動記憶體管理

跨度不管理其指向的記憶體。 這意味著如果釋放了底層受控記憶體或超出作用域,使用 Span將導致未定義的行為或潛在的崩潰。 開發人員在使用 Span 時,需要確保底層記憶體仍然有效。.

1.2 無垃圾回收

自從 Span不擁有記憶體,因此不受垃圾回收影響。 因此,當您處理堆疊分配的記憶體或生命週期比 Span 更短的記憶體時,需要小心。本身。

1.3 範圍檢查已停用

跨度和 ReadOnly跨度預設不進行邊界檢查。 如果不小心使用,這可能會導致存取無效的記憶體位置。 開發人員需手動確保對 Span 的操作保持在底層記憶體的範圍內。

1.4 不支援非連續記憶體

跨度設計用於處理連續的記憶體。 如果您有非連續記憶體或需要表示更複雜的數據結構,Span可能不是最合適的選擇。

1.5 並非所有操作都受支持

當範圍支持許多常見的操作,如切片、索引和迭代,但並非所有操作都被支持。 例如,您無法調整 Span 的大小並且不允許涉及更改底層記憶體長度的某些操作。

1.6 有限平台相容性

當範圍是 .NET Standard 和 .NET Core 的一部分,它可能並不在所有平台或環境中可用。 確保您的目標平台支持 Span 是至關重要的。如果你打算在程式碼中使用它。

非連續記憶體緩衝區

2.1 對非連續記憶體的有限支持

唯讀範圍主要設計目的是與連續的記憶體塊或緩衝區無縫配合。 當涉及非連續記憶體緩衝區或具有記憶體間隙的資料結構時,它可能不是最合適的選擇。

2.2 結構限制

某些依賴非連續記憶體的資料結構或情境可能與 ReadOnlySpan 不太相符。. 例如,由於 ReadOnlySpan 需要連續記憶體,像是鏈結串列或圖結構這樣的數據結構可能不太合適。.

2.3 複雜指標操作

在涉及非連續記憶體的情況中,特別是那些需要複雜指針運算的情形,ReadOnlySpan可能無法像 C++ 等語言中的原始指針那樣提供相同的低層控制和靈活性。 在這種情況下,使用指針的不安全代碼可能更為合適。

2.4 某些 API 缺乏直接支援

與連續記憶體相似,請注意並非所有的 API 或函式庫都能直接支援由 ReadOnlySpan 表示的非連續記憶體。. 適應這些情況可能需要額外的中間步驟或轉換以確保相容性。

跨度和非托管記憶體

在 C# 中,Span 可以有效地與非受控記憶體一起使用,以受控且高效的方式執行記憶體相關操作。 非受控記憶體是指不受 .NET 執行環境的垃圾回收器管理的記憶體,通常涉及使用本機記憶體的配置和釋放。 以下是如何在 C# 中使用 Span 與非受控記憶體。

分配非托管記憶體

要分配非受控記憶體,您可以使用 System.Runtime.InteropServices.MemoryMarshal 類。 Marshal.AllocHGlobal 方法分配記憶體並返回指向已分配區塊的指標。 分配的記憶體或記憶體地址保存在 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);
    }
}
using System;
using System.Runtime.InteropServices;
class Program
{
    static void Main()
    {
        const int bufferSize = 100;
        IntPtr unmanagedMemory = Marshal.AllocHGlobal(bufferSize);
        // Create a Span from the unmanaged memory
        Span<byte> span = new Span<byte>(unmanagedMemory.ToPointer(), bufferSize);
        // Use the Span as needed...
        // Don't forget to free the unmanaged memory when done
        Marshal.FreeHGlobal(unmanagedMemory);
    }
}
Imports System
Imports System.Runtime.InteropServices
Friend Class Program
	Shared Sub Main()
		Const bufferSize As Integer = 100
		Dim unmanagedMemory As IntPtr = Marshal.AllocHGlobal(bufferSize)
		' Create a Span from the unmanaged memory
		Dim span As New Span(Of Byte)(unmanagedMemory.ToPointer(), bufferSize)
		' Use the Span as needed...
		' Don't forget to free the unmanaged memory when done
		Marshal.FreeHGlobal(unmanagedMemory)
	End Sub
End Class
VB   C#

在上面的源代碼中,我們使用 Marshal.AllocHGlobal 分配一塊非託管記憶體,然後創建一個 Span使用從非管理記憶體獲得的指標。 這使我們可以使用熟悉的 Span API 操作非受管記憶體。 需要注意的是,在處理非受控記憶體時,您需要負責管理記憶體的分配和釋放。

將數據複製到非託管記憶體及從非託管記憶體複製數據

Span 提供了像 Slice、CopyTo 和 ToArray 這樣的方法,這些方法可以用來在受管理和非受管理的記憶體之間高效地複製資料。

using System;
using System.Runtime.InteropServices;
class Program
{
    static void Main()
    {
        // Managed array to copy data from
        int[] sourceArray = { 1, 2, 3, 4, 5 };
        // Allocate unmanaged memory for the destination data
        IntPtr destinationPointer = MemoryMarshal.Allocate<int>(sourceArray.Length);
        try
        {
            // Create a Span<int> from the source array
            Span<int> sourceSpan = sourceArray;
            // Create a Span<int> from the allocated unmanaged memory
            Span<int> destinationSpan = MemoryMarshal.Cast<int, byte>(destinationPointer, sourceArray.Length);
            // Copy data from the source Span<int> to the destination Span<int>
            sourceSpan.CopyTo(destinationSpan);
            // Print the values in the destination memory
            Console.WriteLine("Values in the destination memory:");
            foreach (var value in destinationSpan)
            {
                Console.Write($"{value} ");
            }
        }
        finally
        {
            // Deallocate the unmanaged memory when done
            MemoryMarshal.Free(destinationPointer);
        }
    }
}
using System;
using System.Runtime.InteropServices;
class Program
{
    static void Main()
    {
        // Managed array to copy data from
        int[] sourceArray = { 1, 2, 3, 4, 5 };
        // Allocate unmanaged memory for the destination data
        IntPtr destinationPointer = MemoryMarshal.Allocate<int>(sourceArray.Length);
        try
        {
            // Create a Span<int> from the source array
            Span<int> sourceSpan = sourceArray;
            // Create a Span<int> from the allocated unmanaged memory
            Span<int> destinationSpan = MemoryMarshal.Cast<int, byte>(destinationPointer, sourceArray.Length);
            // Copy data from the source Span<int> to the destination Span<int>
            sourceSpan.CopyTo(destinationSpan);
            // Print the values in the destination memory
            Console.WriteLine("Values in the destination memory:");
            foreach (var value in destinationSpan)
            {
                Console.Write($"{value} ");
            }
        }
        finally
        {
            // Deallocate the unmanaged memory when done
            MemoryMarshal.Free(destinationPointer);
        }
    }
}
Imports System
Imports System.Runtime.InteropServices
Friend Class Program
	Shared Sub Main()
		' Managed array to copy data from
		Dim sourceArray() As Integer = { 1, 2, 3, 4, 5 }
		' Allocate unmanaged memory for the destination data
		Dim destinationPointer As IntPtr = MemoryMarshal.Allocate(Of Integer)(sourceArray.Length)
		Try
			' Create a Span<int> from the source array
			Dim sourceSpan As Span(Of Integer) = sourceArray
			' Create a Span<int> from the allocated unmanaged memory
			Dim destinationSpan As Span(Of Integer) = MemoryMarshal.Cast(Of Integer, Byte)(destinationPointer, sourceArray.Length)
			' Copy data from the source Span<int> to the destination Span<int>
			sourceSpan.CopyTo(destinationSpan)
			' Print the values in the destination memory
			Console.WriteLine("Values in the destination memory:")
			For Each value In destinationSpan
				Console.Write($"{value} ")
			Next value
		Finally
			' Deallocate the unmanaged memory when done
			MemoryMarshal.Free(destinationPointer)
		End Try
	End Sub
End Class
VB   C#

在此範例中:

MemoryMarshal.Allocate(sourceArray.Length)為目標數據分配非受控記憶體。 MemoryMarshal.Cast<int, byte>(destinationPointer, sourceArray.Length) 創建 Span從分配的非受控記憶體中。 sourceSpan.CopyTo(目的地範圍)此方法將數據從受管陣列複製到非受管記憶體中。 為了驗證複製操作,將目的地記憶體中的值列印出來。 MemoryMarshal.Free(目標指標)該方法用於在完成後釋放非託管內存。

使用不安全程式碼

在處理非受控記憶體時,您也可以使用帶指標的非安全代碼。 在此類情況下,您可以使用 Unsafe.AsPointer 從 Span 獲取指針。()方法。

using System;
using System.Runtime.InteropServices;
class Program
{
    static void Main()
    {
        const int bufferSize = 100;
        IntPtr unmanagedMemory = Marshal.AllocHGlobal(bufferSize);
        // Create a Span from the unmanaged memory
        Span<byte> span = new Span<byte>(unmanagedMemory.ToPointer(), bufferSize);
        // Use unsafe code to work with pointers
        // ref t
        unsafe
        {
            byte* pointer = (byte*)Unsafe.AsPointer(ref struct MemoryMarshal.GetReference(span));
            // Use the pointer as needed...
        }
        // Don't forget to free the unmanaged memory when done
        Marshal.FreeHGlobal(unmanagedMemory);
    }
}
using System;
using System.Runtime.InteropServices;
class Program
{
    static void Main()
    {
        const int bufferSize = 100;
        IntPtr unmanagedMemory = Marshal.AllocHGlobal(bufferSize);
        // Create a Span from the unmanaged memory
        Span<byte> span = new Span<byte>(unmanagedMemory.ToPointer(), bufferSize);
        // Use unsafe code to work with pointers
        // ref t
        unsafe
        {
            byte* pointer = (byte*)Unsafe.AsPointer(ref struct MemoryMarshal.GetReference(span));
            // Use the pointer as needed...
        }
        // Don't forget to free the unmanaged memory when done
        Marshal.FreeHGlobal(unmanagedMemory);
    }
}
Imports System
Imports System.Runtime.InteropServices
Friend Class Program
	Shared Sub Main()
		Const bufferSize As Integer = 100
		Dim unmanagedMemory As IntPtr = Marshal.AllocHGlobal(bufferSize)
		' Create a Span from the unmanaged memory
		Dim span As New Span(Of Byte)(unmanagedMemory.ToPointer(), bufferSize)
		' Use unsafe code to work with pointers
		' ref t
'INSTANT VB TODO TASK: C# 'unsafe' code is not converted by Instant VB:
'		unsafe
'		{
'			byte* pointer = (byte*)Unsafe.AsPointer(ref struct MemoryMarshal.GetReference(span));
'			' Use the pointer as needed...
'		}
		' Don't forget to free the unmanaged memory when done
		Marshal.FreeHGlobal(unmanagedMemory)
	End Sub
End Class
VB   C#

在這個範例中,我們使用 Unsafe.AsPointer 方法從 Span 獲取指標。 這使我們能夠在直接使用指標時使用不安全的代碼。

請記住,在處理非受控記憶體時,正確管理記憶體的分配和釋放至關重要,避免記憶體洩漏。 始終使用適當的方法釋放非受控記憶體,例如 Marshal.FreeHGlobal。(). 此外,使用不安全的代碼時需謹慎,因為如果處理不當,可能會帶來潛在的安全風險。

跨度和非同步方法呼叫

在C#中,將Span與非同步方法調用結合使用是一種強大的組合,尤其是在處理大量數據或I/O操作時。 目標是有效處理異步操作,避免不必要的數據複製。 讓我們探討如何在異步場景中利用 Span:

1. 非同步 I/O 操作:

在處理非同步 I/O 操作時,例如讀取或寫入數據到流,您可以使用 Memory或 範圍以不建立額外緩衝區的方式有效地處理資料。

async Task ProcessDataAsync(Stream stream)
{
    const int bufferSize = 4096;
    byte[] buffer = new byte[bufferSize];
    while (true)
    {
        int bytesRead = await stream.ReadAsync(buffer.AsMemory());
        if (bytesRead == 0)
            break;
        // Process the data using Span without unnecessary copying
        ProcessData(buffer.AsSpan(0, bytesRead));
    }
}
void ProcessData(Span<byte> data)
{
    // Perform operations on the data
}
async Task ProcessDataAsync(Stream stream)
{
    const int bufferSize = 4096;
    byte[] buffer = new byte[bufferSize];
    while (true)
    {
        int bytesRead = await stream.ReadAsync(buffer.AsMemory());
        if (bytesRead == 0)
            break;
        // Process the data using Span without unnecessary copying
        ProcessData(buffer.AsSpan(0, bytesRead));
    }
}
void ProcessData(Span<byte> data)
{
    // Perform operations on the data
}
Async Function ProcessDataAsync(ByVal stream As Stream) As Task
	Const bufferSize As Integer = 4096
	Dim buffer(bufferSize - 1) As Byte
	Do
		Dim bytesRead As Integer = Await stream.ReadAsync(buffer.AsMemory())
		If bytesRead = 0 Then
			Exit Do
		End If
		' Process the data using Span without unnecessary copying
		ProcessData(buffer.AsSpan(0, bytesRead))
	Loop
End Function
Private Sub ProcessData(ByVal data As Span(Of Byte))
	' Perform operations on the data
End Sub
VB   C#

在此示例中,ReadAsync 方法將資料以非同步的方式從串流讀入緩衝區。 ProcessData 方法然後直接從 Span 處理數據。不用複製到另一個緩衝区。

2. 非同步文件操作:

類似於 I/O 操作,處理非同步文件操作時可以使用 Span 來高效處理數據,而不需額外複製。

async Task ProcessFileAsync(string filePath)
{
    const int bufferSize = 4096;
    using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
    {
        byte[] buffer = new byte[bufferSize];
        while (true)
        {
            int bytesRead = await fileStream.ReadAsync(buffer.AsMemory());
            if (bytesRead == 0)
                break;
            // Process the data using Span without unnecessary copying
            ProcessData(buffer.AsSpan(0, bytesRead));
        }
    }
}
void ProcessData(Span<byte> data)
{
    // Perform operations on the data
}
async Task ProcessFileAsync(string filePath)
{
    const int bufferSize = 4096;
    using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
    {
        byte[] buffer = new byte[bufferSize];
        while (true)
        {
            int bytesRead = await fileStream.ReadAsync(buffer.AsMemory());
            if (bytesRead == 0)
                break;
            // Process the data using Span without unnecessary copying
            ProcessData(buffer.AsSpan(0, bytesRead));
        }
    }
}
void ProcessData(Span<byte> data)
{
    // Perform operations on the data
}
Async Function ProcessFileAsync(ByVal filePath As String) As Task
	Const bufferSize As Integer = 4096
	Using fileStream As New FileStream(filePath, FileMode.Open, FileAccess.Read)
		Dim buffer(bufferSize - 1) As Byte
		Do
			Dim bytesRead As Integer = Await fileStream.ReadAsync(buffer.AsMemory())
			If bytesRead = 0 Then
				Exit Do
			End If
			' Process the data using Span without unnecessary copying
			ProcessData(buffer.AsSpan(0, bytesRead))
		Loop
	End Using
End Function
Private Sub ProcessData(ByVal data As Span(Of Byte))
	' Perform operations on the data
End Sub
VB   C#

這裡,ReadAsync 方法從檔案流中讀取數據到緩衝區,而 ProcessData 方法直接從 Span 中處理數據。.

3. 非同步任務處理:

在處理產生或消費數據的異步任務時,您可以使用 Memory或 範圍避免不必要的複製。

async Task<int> ProcessDataAsync(int[] data)
{
    // Asynchronous processing of data
    await Task.Delay(1000);
    // Returning the length of the processed data
    return data.Length;
}
async Task Main()
{
    int[] inputData = Enumerable.Range(1, 1000).ToArray();
    // Process the data asynchronously without copying
    int processedLength = await ProcessDataAsync(inputData.AsMemory());
    Console.WriteLine($"Processed data length: {processedLength}");
}
async Task<int> ProcessDataAsync(int[] data)
{
    // Asynchronous processing of data
    await Task.Delay(1000);
    // Returning the length of the processed data
    return data.Length;
}
async Task Main()
{
    int[] inputData = Enumerable.Range(1, 1000).ToArray();
    // Process the data asynchronously without copying
    int processedLength = await ProcessDataAsync(inputData.AsMemory());
    Console.WriteLine($"Processed data length: {processedLength}");
}
Async Function ProcessDataAsync(ByVal data() As Integer) As Task(Of Integer)
	' Asynchronous processing of data
	Await Task.Delay(1000)
	' Returning the length of the processed data
	Return data.Length
End Function
Async Function Main() As Task
	Dim inputData() As Integer = Enumerable.Range(1, 1000).ToArray()
	' Process the data asynchronously without copying
	Dim processedLength As Integer = Await ProcessDataAsync(inputData.AsMemory())
	Console.WriteLine($"Processed data length: {processedLength}")
End Function
VB   C#

在此範例中,ProcessDataAsync 方法會異步處理數據,並且在不需要額外複製的情況下返回處理後數據的長度。

介紹 IronPDF

IronPDF 庫概覽是最新的C# PDF庫來自Iron Software可以使用 C# 代碼動態生成美觀的 PDF 文件。 IronPDF 提供多種功能,例如從 HTML 生成 PDF、將 HTML 內容轉換為 PDF、合併或拆分 PDF 文件等。

IronPDF 的主要功能是其HTML 轉換為 PDF 功能,這樣可以保留佈局和樣式。 它可以從網絡內容生成 PDF,非常適合報告、發票和文檔。 此工具支持將 HTML 文件、URL 和 HTML 字串轉換為 PDF 文件。

using IronPdf;

class Program
{
    static void Main(string[] args)
    {
        var renderer = new ChromePdfRenderer();

        // 1. Convert HTML String to PDF
        var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
        var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
        pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");

        // 2. Convert HTML File to PDF
        var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
        var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
        pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");

        // 3. Convert URL to PDF
        var url = "http://ironpdf.com"; // Specify the URL
        var pdfFromUrl = renderer.RenderUrlAsPdf(url);
        pdfFromUrl.SaveAs("URLToPDF.pdf");
    }
}
using IronPdf;

class Program
{
    static void Main(string[] args)
    {
        var renderer = new ChromePdfRenderer();

        // 1. Convert HTML String to PDF
        var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
        var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
        pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");

        // 2. Convert HTML File to PDF
        var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
        var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
        pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");

        // 3. Convert URL to PDF
        var url = "http://ironpdf.com"; // Specify the URL
        var pdfFromUrl = renderer.RenderUrlAsPdf(url);
        pdfFromUrl.SaveAs("URLToPDF.pdf");
    }
}
Imports IronPdf

Friend Class Program
	Shared Sub Main(ByVal args() As String)
		Dim renderer = New ChromePdfRenderer()

		' 1. Convert HTML String to PDF
		Dim htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>"
		Dim pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent)
		pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf")

		' 2. Convert HTML File to PDF
		Dim htmlFilePath = "path_to_your_html_file.html" ' Specify the path to your HTML file
		Dim pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath)
		pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf")

		' 3. Convert URL to PDF
		Dim url = "http://ironpdf.com" ' Specify the URL
		Dim pdfFromUrl = renderer.RenderUrlAsPdf(url)
		pdfFromUrl.SaveAs("URLToPDF.pdf")
	End Sub
End Class
VB   C#

安裝

IronPDF 可以使用以下方法安裝:IronPDF 的 NuGet 套件管理器控制台或使用 Visual Studio 套件管理器。

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

C# Span(如何適用於開發者):圖 1 - 透過在 NuGet 套件管理員的搜尋欄中搜尋 ironpdf 來安裝 IronPDF。

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

在此範例中,我們使用SpanIronPDF來生成 PDF 文件。

輸出:

C# Span(如何為開發者工作):圖2 - 控制台輸出

生成的 PDF:

C# Span(對開發人員的運作方式):圖 3 - PDF 輸出

授權(免費試用可用)

IronPDF 授權資訊. 此鍵需要放置在 appsettings.json 中。

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

提供您的電子郵件以獲取試用許可證。

結論

跨度在 C# 中提供了一種強大且高效的内存處理方式,在性能和靈活性方面提供了優勢。 其非擁有且連續的特性,特別適合在需要最大限度減少記憶體分配和複製的情境下使用。 通過利用 Span,開發人員可以在從字串操作到高效能數字處理的各類應用中實現更好的效能。 通過了解其功能並考慮其限制,開發人員可以利用 Span。用於安全且有效地執行各種記憶體操作任務。 隨著IronPDF 庫概覽,它可以用來生成出色的 PDF 文件,無需使用 await 和 yield 邊界。

請訪問IronPDF 的快速入門文檔頁面頁面。

< 上一頁
C# IDE(開發人員如何使用它)
下一個 >
Opentelemetry C#(開發人員如何使用)