.NET 幫助

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

發佈 2024年3月6日
分享:

跨度 是在 C# 7.2 中作為 Span 的一部分引入的一種類型結構在 System 命名空間中。它被設計用來表示任意記憶體的連續區域。不像陣列或類似受管理堆集合,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

儘管 Span是可變的並允許對基礎數據進行修改,ReadOnlySpan是一種不可變的記憶體視圖。它提供對連續記憶體區域的唯讀介面,適用於只需讀取資料而無需修改的情況。

以下是一些關鍵點。

1. 只讀視圖

正如其名稱所示,ReadOnlySpan讓你建立一個記憶體區塊的唯讀視圖。這意味著你不能通過ReadOnlySpan修改元素。.

2. 記憶體表示

像 Span,ReadOnlySpan不擁有它指向的記憶體。它指的是現有的記憶體,可以指向陣列、堆棧分配的記憶體或本地記憶體。

3. 性能優勢

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

4. 無邊界檢查

與 Span 類似,ReadOnlySpan不執行邊界檢查。開發人員有責任確保操作在底層記憶體的範圍內進行。

5. 使用陣列切片

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

範例

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. 使用子字串

使用 Slice 在 ReadOnlySpan 上

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

3. 將子字串傳遞給方法

將 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. 在字串中搜尋

ReadOnlySpan在字串中使用 IndexOf 搜尋().

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

5. 使用記憶體映射檔案

ReadOnlySpan使用記憶體對映文件可以更有效率。

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. 高效的字串操作

ReadOnlySpan可用於高效的字串操作。

// 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. 傳遞子字串給 API

在使用操作字符跨度的外部庫或 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#

唯讀範圍提供了一種更有效地處理字串的方法,特別是在應該最小化記憶體配置和複製的情況下。這是一個優化性能關鍵代碼的強大工具,尤其在處理大量字串數據時特別有益。

Span 限制

儘管在 C# 中,Span 是一個具有許多優點的強大功能,但在連續和非連續內存的上下文中,它確實存在某些限制和注意事項。讓我們來探討這些限制:

連續記憶體緩衝區

1.1 無自動內存管理

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

1.2 沒有垃圾回收

由於 Span不擁有記憶體,不受垃圾回收影響。因此,在使用堆疊分配的記憶體或比 Span 壽命更短的記憶體時,需要小心。本身。

1.3 邊界檢查已禁用

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

1.4 不支持非連續記憶體

Span旨在與連續記憶體一起工作。如果您有非連續記憶體或需要表示更複雜的數據結構,Span可能不是最合適的選擇。

1.5 並非所有操作都受支持

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

1.6 限制的平臺相容性

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

非連續記憶體緩衝區

2.1 非連續記憶體的有限支援

ReadOnlySpan主要設計是與連續的記憶體塊或緩衝區無縫配合。對於涉及非連續記憶體緩衝區或內存中有間隙的結構的情況,它可能不是最合適的選擇。

2.2 結構限制

某些依賴非連續記憶體的數據結構或場景可能不適用於 ReadOnlySpan例如,由於 ReadOnlySpan 對連續記憶體的要求,像是鏈接列表或圖結構等數據結構可能不太適合。.

2.3 复杂指针操作

在涉及非连续内存的情况下,特别是需要复杂的指针运算时,ReadOnlySpan可能不會像 C++ 等語言中的原始指針那樣提供同等的低級控制和靈活性。在這種情況下,使用不安全代碼與指針可能更合適。

2.4 某些 API 缺乏直接支持

與連續內存相似,需要注意的是,並非所有 API 或庫都能直接支持由 ReadOnlySpan 代表的非連續內存。. 為了適應這些情況,可能需要額外的中間步驟或轉換來確保相容性。

Span 和非託管記憶體

在 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。()此外,在使用不安全代碼時也需謹慎,因為如果處理不當可能會引入潛在的安全風險。

Span 與非同步方法調用

在 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 可以使用 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,方法是在NuGet包管理器的搜索欄中搜索"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#

在這個例子中,我們使用 Span 以及 IronPDF 來生成一個 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#

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

結論

Span在C#中,提供了一種強大且高效的方式來處理記憶體,在性能和靈活性方面提供了很多好處。其非擁有、連續的特性使其特別適合需要最小化記憶體分配和複製的場景。通過利用Span,開發者可以在各種應用中實現更好的性能,從字串操作到高性能數字處理。通過理解其特性並考慮其限制,開發者可以充分利用Span。用於各種記憶體操作任務的安全高效執行。隨著 IronPDF, 它可以用來生成很棒的 PDF 文件,無需 await 和 yield 邊界。

免費試用 長期使用。如需了解更多關於如何使用IronPDF,請訪問他們的 文檔 頁面。

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

準備開始了嗎? 版本: 2024.10 剛剛發布

免費 NuGet 下載 總下載次數: 10,993,239 查看許可證 >