Span<T> 结构

定义

提供任意内存连续区域的类型安全与内存安全表示形式。

generic <typename T>
public value class Span
[System.Runtime.InteropServices.Marshalling.NativeMarshalling(typeof(System.Runtime.InteropServices.Marshalling.SpanMarshaller<,>))]
public readonly ref struct Span<T>
public readonly ref struct Span<T>
[<System.Runtime.InteropServices.Marshalling.NativeMarshalling(typeof(System.Runtime.InteropServices.Marshalling.SpanMarshaller<,>))>]
type Span<'T> = struct
type Span<'T> = struct
Public Structure Span(Of T)

类型参数

T

Span<T>项的类型。

继承
Span<T>
属性

注解

类型 Span<T> 是一种 结构 ref,它在堆栈上分配,而不是在托管堆上。 Ref 结构类型存在一些限制,以确保无法将其提升到托管堆,包括不能:

  • 盒装。
  • 分配给类型 Objectdynamic或任何接口版式的变量。
  • 引用类型的字段。
  • awaityield边界使用。

此外,调用两个方法, Equals(Object)GetHashCode引发一个 NotSupportedException

Important

因为它是仅堆栈类型, Span<T> 因此不适用于许多需要存储对堆上的缓冲区的引用的方案。 例如,执行异步方法调用的例程也是如此。 对于此类方案,可以使用互补 System.Memory<T>System.ReadOnlyMemory<T> 类型。

对于表示不可变或只读结构的跨度,请使用 System.ReadOnlySpan<T>

Memory

Span<T> 表示任意内存的连续区域。 Span<T>实例通常用于保存数组或数组的一部分的元素。 但是,与数组不同,Span<T> 实例可以指向托管内存、本机内存或堆栈上管理的内存。 以下示例从数组创建一个 Span<Byte>

// Create a span over an array.
var array = new byte[100];
var arraySpan = new Span<byte>(array);

byte data = 0;
for (int ctr = 0; ctr < arraySpan.Length; ctr++)
    arraySpan[ctr] = data++;

int arraySum = 0;
foreach (var value in array)
    arraySum += value;

Console.WriteLine($"The sum is {arraySum}");
// Output:  The sum is 4950
// Create a span over an array.
let array = Array.zeroCreate<byte> 100
let arraySpan = Span<byte> array

let mutable data = 0uy
for i = 0 to arraySpan.Length - 1 do
    arraySpan[i] <- data
    data <- data + 1uy

let mutable arraySum = 0
for value in array do
    arraySum <- arraySum + int value

printfn $"The sum is {arraySum}"
// Output:  The sum is 4950

以下示例从 100 字节的本机内存创建一个 `Span<Byte>`:

// Create a span from native memory.
var native = Marshal.AllocHGlobal(100);
Span<byte> nativeSpan;
unsafe
{
    nativeSpan = new Span<byte>(native.ToPointer(), 100);
}
byte data = 0;
for (int ctr = 0; ctr < nativeSpan.Length; ctr++)
    nativeSpan[ctr] = data++;

int nativeSum = 0;
foreach (var value in nativeSpan)
    nativeSum += value;

Console.WriteLine($"The sum is {nativeSum}");
Marshal.FreeHGlobal(native);
// Output:  The sum is 4950
// Create a span from native memory.
let native = Marshal.AllocHGlobal 100
let nativeSpan = Span<byte>(native.ToPointer(), 100)

let mutable data = 0uy
for i = 0 to nativeSpan.Length - 1 do
    nativeSpan[i] <- data
    data <- data + 1uy

let mutable nativeSum = 0
for value in nativeSpan do
    nativeSum <- nativeSum + int value

printfn $"The sum is {nativeSum}"
Marshal.FreeHGlobal native
// Output:  The sum is 4950

以下示例使用 C# stackalloc 关键字在堆栈上分配 100 字节内存:

// Create a span on the stack.
byte data = 0;
Span<byte> stackSpan = stackalloc byte[100];
for (int ctr = 0; ctr < stackSpan.Length; ctr++)
    stackSpan[ctr] = data++;

int stackSum = 0;
foreach (var value in stackSpan)
    stackSum += value;

Console.WriteLine($"The sum is {stackSum}");
// Output:  The sum is 4950
    // Create a span on the stack.
    let mutable data = 0uy
    let stackSpan = 
        let p = NativeInterop.NativePtr.stackalloc<byte> 100 |> NativeInterop.NativePtr.toVoidPtr
        Span<byte>(p, 100)

    for i = 0 to stackSpan.Length - 1 do
        stackSpan[i] <- data
        data <- data + 1uy

    let mutable stackSum = 0
    for value in stackSpan do
        stackSum <- stackSum + int value

    printfn $"The sum is {stackSum}"
// Output:  The sum is 4950

由于Span<T>是任意内存块的抽象,因此无论所封装的内存类型如何,Span<T>类型的方法和带有Span<T>参数的方法都可以操作任何Span<T>对象。 例如,初始化范围并计算其元素之和的每个单独部分都可以重构为单个初始化和计算方法,如以下示例所示:

public static void WorkWithSpans()
{
    // Create a span over an array.
    var array = new byte[100];
    var arraySpan = new Span<byte>(array);

    InitializeSpan(arraySpan);
    Console.WriteLine($"The sum is {ComputeSum(arraySpan):N0}");

    // Create an array from native memory.
    var native = Marshal.AllocHGlobal(100);
    Span<byte> nativeSpan;
    unsafe
    {
        nativeSpan = new Span<byte>(native.ToPointer(), 100);
    }

    InitializeSpan(nativeSpan);
    Console.WriteLine($"The sum is {ComputeSum(nativeSpan):N0}");

    Marshal.FreeHGlobal(native);

    // Create a span on the stack.
    Span<byte> stackSpan = stackalloc byte[100];

    InitializeSpan(stackSpan);
    Console.WriteLine($"The sum is {ComputeSum(stackSpan):N0}");
}

public static void InitializeSpan(Span<byte> span)
{
    byte value = 0;
    for (int ctr = 0; ctr < span.Length; ctr++)
        span[ctr] = value++;
}

public static int ComputeSum(Span<byte> span)
{
    int sum = 0;
    foreach (var value in span)
        sum += value;

    return sum;
}
// The example displays the following output:
//    The sum is 4,950
//    The sum is 4,950
//    The sum is 4,950
open System
open System.Runtime.InteropServices
open FSharp.NativeInterop

// Package FSharp.NativeInterop.NativePtr.stackalloc for reuse.
let inline stackalloc<'a when 'a: unmanaged> length : Span<'a> =
    let voidPointer = NativePtr.stackalloc<'a> length |> NativePtr.toVoidPtr
    Span<'a>(voidPointer, length)

let initializeSpan (span: Span<byte>) =
    let mutable value = 0uy
    for i = 0 to span.Length - 1 do
        span[i] <- value
        value <- value + 1uy

let computeSum (span: Span<byte>) =
    let mutable sum = 0
    for value in span do
        sum <- sum + int value
    sum

let workWithSpans () =
    // Create a span over an array.
    let array = Array.zeroCreate<byte> 100
    let arraySpan = Span<byte> array

    initializeSpan arraySpan
    printfn $"The sum is {computeSum arraySpan:N0}"

    // Create an array from native memory.
    let native = Marshal.AllocHGlobal 100
    let nativeSpan = Span<byte>(native.ToPointer(), 100)

    initializeSpan nativeSpan
    printfn $"The sum is {computeSum nativeSpan:N0}"

    Marshal.FreeHGlobal native

    // Create a span on the stack.
    let stackSpan = stackalloc 100

    initializeSpan stackSpan
    printfn $"The sum is {computeSum stackSpan:N0}"

// The example displays the following output:
//    The sum is 4,950
//    The sum is 4,950
//    The sum is 4,950

数组

当它包装数组时,Span<T>可以包装整个数组,就像“内存”部分中的示例一样。 因为它支持切片, Span<T> 因此也可以指向数组中的任何连续范围。

以下示例创建 10 个元素整数数组的中间 5 个元素的切片。 请注意,代码将切片中每个整数的值加倍。 如输出所示,范围所做的更改将反映在数组的值中。

using System;

var array = new int[] { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 };
var slice = new Span<int>(array, 2, 5);
for (int ctr = 0; ctr < slice.Length; ctr++)
    slice[ctr] *= 2;

// Examine the original array values.
foreach (var value in array)
    Console.Write($"{value}  ");
Console.WriteLine();

// The example displays the following output:
//      2  4  12  16  20  24  28  16  18  20
module Program

open System

[<EntryPoint>]
let main _ =
    let array = [| 2; 4; 6; 8; 10; 12; 14; 16; 18; 20 |]
    let slice = Span<int>(array, 2, 5)
    for i = 0 to slice.Length - 1 do
        slice[i] <- slice[i] * 2

    // Examine the original array values.
    for value in array do
        printf $"{value}  "
    printfn ""
    0
// The example displays the following output:
//      2  4  12  16  20  24  28  16  18  20

切片

Span<T> 包括 Slice 方法的两个重载,这些重载在当前跨度中,从指定的索引开始,形成一个切片。 这样,便可以将一 Span<T> 组逻辑区块中的数据视为一组逻辑区块,这些区块可由数据处理管道的一部分根据需要进行处理,且性能影响最小。 例如,由于新式服务器协议通常是基于文本的,因此对字符串和子字符串的操作尤其重要。 在类中 String ,提取子字符串 Substring的主要方法是。 对于依赖于大量字符串操作的数据管道,其使用会带来一些性能损失,因为它:

  1. 创建一个新字符串来保存子字符串。
  2. 将原始字符串中的字符子集复制到新字符串。

可以使用任一Span<T>ReadOnlySpan<T>操作来消除此分配和复制操作,如以下示例所示:

using System;

class Program2
{
    static void Run()
    {
        string contentLength = "Content-Length: 132";
        var length = GetContentLength(contentLength.ToCharArray());
        Console.WriteLine($"Content length: {length}");
    }

    private static int GetContentLength(ReadOnlySpan<char> span)
    {
        var slice = span.Slice(16);
        return int.Parse(slice);
    }
}
// Output:
//      Content length: 132
module Program2

open System

let getContentLength (span: ReadOnlySpan<char>) =
    let slice = span.Slice 16
    Int32.Parse slice

let contentLength = "Content-Length: 132"
let length = getContentLength (contentLength.ToCharArray())
printfn $"Content length: {length}"
// Output:
//      Content length: 132

构造函数

名称 说明
Span<T>(T)

围绕指定的引用创建长度 1 的新 Span<T> 长度。

Span<T>(T[], Int32, Int32)

创建一个新 Span<T> 对象,该对象包含从指定索引开始的数组的指定数量的元素。

Span<T>(T[])

在整个指定数组上创建一个新 Span<T> 对象。

Span<T>(Void*, Int32)

从指定内存地址开始的Span<T>指定数量的元素创建一个新T对象。

属性

名称 说明
Empty

返回一个空 Span<T> 对象。

IsEmpty

返回一个值,该值指示当前 Span<T> 是否为空。

Item[Int32]

获取指定从零开始的索引处的元素。

Length

返回当前范围的长度。

方法

名称 说明
Clear()

清除此 Span<T> 对象的内容。

CopyTo(Span<T>)

将此内容 Span<T> 复制到目标 Span<T>中。

Equals(Object)
已过时.
已过时.

不支持对此方法的调用。

Fill(T)

用指定的值填充此范围的元素。

GetEnumerator()

返回此 Span<T>枚举器。

GetHashCode()
已过时.

引发 NotSupportedException

GetPinnableReference()

返回对 T 类型的对象的引用,该对象可用于固定。

此方法旨在支持.NET编译器,不应由用户代码调用。

Slice(Int32, Int32)

从指定长度的指定索引处开始,形成当前范围的切片。

Slice(Int32)

形成从指定索引处开始的当前范围的切片。

ToArray()

将此范围的内容复制到新的数组中。

ToString()

返回此 Span<T> 对象的字符串表示形式。

TryCopyTo(Span<T>)

尝试将当前 Span<T> 复制到目标 Span<T> 并返回一个值,该值指示复制操作是否成功。

运营商

名称 说明
Equality(Span<T>, Span<T>)

返回一个值,该值指示两 Span<T> 个对象是否相等。

Implicit(ArraySegment<T> to Span<T>)

定义到 a. 的ArraySegment<T>Span<T>隐式转换。

Implicit(Span<T> to ReadOnlySpan<T>)

定义对 a Span<T>ReadOnlySpan<T>的隐式转换。

Implicit(T[] to Span<T>)

定义数组到 <a0/> 的隐式转换。

Inequality(Span<T>, Span<T>)

返回一个值,该值指示两 Span<T> 个对象是否不相等。

扩展方法

名称 说明
BinarySearch<T,TComparable>(Span<T>, TComparable)

使用指定的Span<T>泛型类型搜索整个排序TComparable的值。

BinarySearch<T,TComparer>(Span<T>, T, TComparer)

使用指定的泛型类型搜索整个已 Span<T> 排序的指定 TComparer 值。

BinarySearch<T>(Span<T>, IComparable<T>)

使用指定的Span<T>泛型接口搜索整个排序IComparable<T>的值。

CommonPrefixLength<T>(Span<T>, ReadOnlySpan<T>, IEqualityComparer<T>)

查找之间spanother和之间共享的任何常见前缀的长度。

CommonPrefixLength<T>(Span<T>, ReadOnlySpan<T>)

查找之间spanother和之间共享的任何常见前缀的长度。

Contains<T>(Span<T>, T)

指示是否在范围中找到指定的值。

ContainsAny<T>(Span<T>, ReadOnlySpan<T>)

搜索任何指定的 values 匹配项,如果找到,则返回 true 。 如果未找到,则返回 false

ContainsAny<T>(Span<T>, SearchValues<T>)

搜索任何指定的 values 匹配项,如果找到,则返回 true 。 如果未找到,则返回 false

ContainsAny<T>(Span<T>, T, T, T)

搜索指定范围或指定范围中的匹配项value0value1value2

ContainsAny<T>(Span<T>, T, T)

搜索匹配项 value0value1如果找到,则返回 true 。 如果未找到,则返回 false

ContainsAnyExcept<T>(Span<T>, ReadOnlySpan<T>)

搜索指定范围中除指定 values值以外的任何值。

ContainsAnyExcept<T>(Span<T>, SearchValues<T>)

搜索指定范围中除指定 values值以外的任何值。

ContainsAnyExcept<T>(Span<T>, T, T, T)

搜索除 /a0> 以外的任何值或

ContainsAnyExcept<T>(Span<T>, T, T)

搜索指定范围中除其他值以外的value0任何值。value1

ContainsAnyExcept<T>(Span<T>, T)

搜索指定范围中除指定 value值以外的任何值。

ContainsAnyExceptInRange<T>(Span<T>, T, T)

搜索介于和非独占范围内lowInclusivehighInclusive的任何值。

ContainsAnyInRange<T>(Span<T>, T, T)

搜索介于 lowInclusivehighInclusive非独占范围内的任何值,如果找到,则返回 true 。 如果未找到,则返回 false

Count<T>(Span<T>, ReadOnlySpan<T>)

计算指定 value 在 . span中发生的次数。

Count<T>(Span<T>, T)

计算指定 value 在 . span中发生的次数。

EndsWith<T>(Span<T>, ReadOnlySpan<T>)

确定指定的序列是否出现在范围末尾。

IndexOf<T>(Span<T>, ReadOnlySpan<T>)

搜索指定的序列并返回其第一个匹配项的索引。

IndexOf<T>(Span<T>, T)

搜索指定的值并返回其第一个匹配项的索引。

IndexOfAny<T>(Span<T>, ReadOnlySpan<T>)

搜索任何指定值的第一个索引。

IndexOfAny<T>(Span<T>, SearchValues<T>)

搜索任何指定值的第一个索引。

IndexOfAny<T>(Span<T>, T, T, T)

搜索任何指定值的第一个索引。

IndexOfAny<T>(Span<T>, T, T)

搜索任何指定值的第一个索引。

IndexOfAnyExcept<T>(Span<T>, ReadOnlySpan<T>)

搜索指定值以外的 values任何值的第一个索引。

IndexOfAnyExcept<T>(Span<T>, SearchValues<T>)

搜索指定值以外的 values任何值的第一个索引。

IndexOfAnyExcept<T>(Span<T>, T, T, T)

搜索除任何值以外的 value0任何值的第一个索引, value1或者 value2

IndexOfAnyExcept<T>(Span<T>, T, T)

搜索除两个指定值以外的任何值的第一个索引。

IndexOfAnyExcept<T>(Span<T>, T)

搜索指定值以外的 value任何值的第一个索引。

IndexOfAnyExceptInRange<T>(Span<T>, T, T)

搜索介于和非独占范围内lowInclusivehighInclusive的任何值的第一个索引。

IndexOfAnyInRange<T>(Span<T>, T, T)

搜索介于 lowInclusivehighInclusive非独占范围内任何值的第一个索引。

LastIndexOf<T>(Span<T>, ReadOnlySpan<T>)

搜索指定的序列并返回其最后一个匹配项的索引。

LastIndexOf<T>(Span<T>, T)

搜索指定的值并返回其最后一个匹配项的索引。

LastIndexOfAny<T>(Span<T>, ReadOnlySpan<T>)

搜索任何指定值的最后一个索引。

LastIndexOfAny<T>(Span<T>, SearchValues<T>)

搜索任何指定值的最后一个索引。

LastIndexOfAny<T>(Span<T>, T, T, T)

搜索任何指定值的最后一个索引。

LastIndexOfAny<T>(Span<T>, T, T)

搜索任何指定值的最后一个索引。

LastIndexOfAnyExcept<T>(Span<T>, ReadOnlySpan<T>)

搜索指定值以外的 values任何值的最后一个索引。

LastIndexOfAnyExcept<T>(Span<T>, SearchValues<T>)

搜索指定值以外的 values任何值的最后一个索引。

LastIndexOfAnyExcept<T>(Span<T>, T, T, T)

搜索指定 value0值以外的任何值的最后一个索引, value1value2

LastIndexOfAnyExcept<T>(Span<T>, T, T)

搜索除指定value0value1值以外的任何值的最后一个索引。

LastIndexOfAnyExcept<T>(Span<T>, T)

搜索指定值以外的 value任何值的最后一个索引。

LastIndexOfAnyExceptInRange<T>(Span<T>, T, T)

搜索介于和非独占范围内lowInclusivehighInclusive的任何值的最后一个索引。

LastIndexOfAnyInRange<T>(Span<T>, T, T)

搜索介于和lowInclusive非独占范围内highInclusive任何值的最后一个索引。

Overlaps<T>(Span<T>, ReadOnlySpan<T>, Int32)

确定范围和只读跨度是否在内存中重叠,并输出元素偏移量。

Overlaps<T>(Span<T>, ReadOnlySpan<T>)

确定范围和只读跨度是否在内存中重叠。

Replace<T>(Span<T>, T, T, IEqualityComparer<T>)

将所有 oldValue 项都替换为 newValue

Replace<T>(Span<T>, T, T)

将所有 oldValue 项都替换为 newValue

ReplaceAny<T>(Span<T>, SearchValues<T>, T)

span替换为任何元素valuesnewValue的所有匹配项。

ReplaceAnyExcept<T>(Span<T>, SearchValues<T>, T)

span替换所有元素(而非其中的valuesnewValue元素)。

Reverse<T>(Span<T>)

反转整个跨度中的元素序列。

SequenceCompareTo<T>(Span<T>, ReadOnlySpan<T>)

通过使用 IComparable{T} 比较元素来确定范围和只读范围的相对顺序。CompareTo(T)。

SequenceEqual<T>(Span<T>, ReadOnlySpan<T>, IEqualityComparer<T>)

通过使用一个比较元素来确定两个 IEqualityComparer<T>序列是否相等。

SequenceEqual<T>(Span<T>, ReadOnlySpan<T>)

通过使用 IEquatable{T} 比较元素,确定范围和只读跨度是否相等。等于(T)。

Sort<T,TComparer>(Span<T>, TComparer)

使用 .. 对整个 Span<T> 元素进行 TComparer排序。

Sort<T>(Span<T>, Comparison<T>)

使用指定的Span<T>元素对整个Comparison<T>元素进行排序。

Sort<T>(Span<T>)

使用Span<T>每个元素的IComparable<T>实现对整个元素Span<T>进行排序。

Sort<TKey,TValue,TComparer>(Span<TKey>, Span<TValue>, TComparer)

根据第 Span<T> 一个使用指定的比较器中的键对范围(一个包含键,另一个包含相应项)进行排序。

Sort<TKey,TValue>(Span<TKey>, Span<TValue>, Comparison<TKey>)

根据第 Span<T> 一次使用指定比较的键对范围(一个包含键,另一个包含相应项)进行排序。

Sort<TKey,TValue>(Span<TKey>, Span<TValue>)

根据第 Span<T> 一次使用 IComparable<T> 每个键的实现,对一对范围(一个包含键,另一个包含相应项)进行排序。

StartsWith<T>(Span<T>, ReadOnlySpan<T>)

确定指定的序列是否出现在范围开头。

ToImmutableArray<T>(Span<T>)

将范围转换为不可变数组。

Trim<T>(Span<T>, ReadOnlySpan<T>)

从范围中移除在只读跨度中指定的一组元素的所有前导和尾随匹配项。

Trim<T>(Span<T>, T)

从范围中删除指定元素的所有前导和尾随匹配项。

TrimEnd<T>(Span<T>, ReadOnlySpan<T>)

从范围中移除在只读跨度中指定的一组元素的所有尾随匹配项。

TrimEnd<T>(Span<T>, T)

从范围中删除指定元素的所有尾随匹配项。

TrimStart<T>(Span<T>, ReadOnlySpan<T>)

从范围中移除在只读跨度中指定的一组元素的所有前导事件。

TrimStart<T>(Span<T>, T)

从范围中删除指定元素的所有前导匹配项。

适用于

另请参阅