C# 12 中的 InlineArray 特性
Intro
C# 12 引入了一个 InlineArray
特性,利用这一特性,我们可以更方便地类数组的结构体,可以代替原来要使用非安全代码的 fixed size buffer
Sample
来看一个简单的使用示例吧
InlineArrayAttribute
声明示例:
[InlineArray(10)]
file struct MyArray
{
// required
private int _element;
}
使用 InlineArray
需要指定 size,也就是 array 的长度,并且我们需要声明一个字段
使用示例如下:
var arr = new MyArray();
for (var i = 0; i < 10; i++)
{
arr[i] = i;
}
foreach (var i in arr)
{
Console.Write(i);
Console.Write(",");
}
Console.WriteLine();
ReadOnlySpan<int> span = arr;
foreach (var i in span)
{
Console.Write(i);
Console.Write(",");
}
Console.WriteLine();
foreach (var i in arr[^2..])
{
Console.Write(i);
Console.Write(",");
}
Console.WriteLine();
Console.WriteLine(arr[^1]);
// error CS0021: Cannot apply indexing with [] to an expression of type 'MyArray'
// if (arr is [0,1,..])
// Console.WriteLine("StartsWith 0, 1");
if (span is [0,1,..])
Console.WriteLine("StartsWith 0, 1");
// error CS9174: Cannot initialize type 'MyArray' with a collection expression because the type is not constructible.
// arr = [1, 2, 3, 4, 5];
span = [1,2,3,4,5];
foreach (var item in span)
{
Console.Write(item);
Console.Write(",");
}
从这个示例可以看得出来,我们可以像使用数组一样使用,同时我们可以直接隐式转换成 Span
和 ReadOnlySpan
并且可以使用 Index
和 Range
操作符
但是目前暂时不能直接使用集合表达式和 list pattern,但是我们可以转成 span 之后再使用
输出结果如下:
Under the cover
反编译看下实际的代码
[InlineArray(10)]
internal struct <InlineArraySample>FF44828C7B01D979B4292C74D526F2DC0220258319544ADFC71435C372F31B507__MyArray
{
// Token: 0x04000003 RID: 3
private int _element;
}
public static class InlineArraySample
{
// Token: 0x06000017 RID: 23 RVA: 0x00002668 File Offset: 0x00000868
public unsafe static void MainTest()
{
<InlineArraySample>FF44828C7B01D979B4292C74D526F2DC0220258319544ADFC71435C372F31B507__MyArray arr = default(<InlineArraySample>FF44828C7B01D979B4292C74D526F2DC0220258319544ADFC71435C372F31B507__MyArray);
for (int i = 0; i < arr.Length; i++)
{
*<PrivateImplementationDetails>.InlineArrayAsSpan<<InlineArraySample>FF44828C7B01D979B4292C74D526F2DC0220258319544ADFC71435C372F31B507__MyArray, int>(ref arr, 10)[i] = i;
}
ref <InlineArraySample>FF44828C7B01D979B4292C74D526F2DC0220258319544ADFC71435C372F31B507__MyArray buffer = ref arr;
for (int m = 0; m < 10; m++)
{
int j = *<PrivateImplementationDetails>.InlineArrayElementRef<<InlineArraySample>FF44828C7B01D979B4292C74D526F2DC0220258319544ADFC71435C372F31B507__MyArray, int>(ref buffer, m);
Console.Write(j);
Console.Write(",");
}
Console.WriteLine();
ReadOnlySpan<int> span = <PrivateImplementationDetails>.InlineArrayAsReadOnlySpan<<InlineArraySample>FF44828C7B01D979B4292C74D526F2DC0220258319544ADFC71435C372F31B507__MyArray, int>(arr, 10);
ReadOnlySpan<int> readOnlySpan = span;
for (int n = 0; n < readOnlySpan.Length; n++)
{
int k = *readOnlySpan[n];
Console.Write(k);
Console.Write(",");
}
Console.WriteLine();
Span<int> span2 = <PrivateImplementationDetails>.InlineArrayAsSpan<<InlineArraySample>FF44828C7B01D979B4292C74D526F2DC0220258319544ADFC71435C372F31B507__MyArray, int>(ref arr, 10).Slice(8, 2);
for (int num = 0; num < span2.Length; num++)
{
int l = *span2[num];
Console.Write(l);
Console.Write(",");
}
Console.WriteLine();
Console.WriteLine(*<PrivateImplementationDetails>.InlineArrayElementRef<<InlineArraySample>FF44828C7B01D979B4292C74D526F2DC0220258319544ADFC71435C372F31B507__MyArray, int>(ref arr, 9));
bool flag = span.Length >= 2 && *span[0] == 0 && *span[1] == 1;
if (flag)
{
Console.WriteLine("StartsWith 0, 1");
}
span = RuntimeHelpers.CreateSpan<int>(fieldof(<PrivateImplementationDetails>.4F6ADDC9659D6FB90FE94B6688A79F2A1FA8D36EC43F8F3E1D9B6528C448A3844).FieldHandle);
ReadOnlySpan<int> readOnlySpan2 = span;
for (int num2 = 0; num2 < readOnlySpan2.Length; num2++)
{
int item = *readOnlySpan2[num2];
Console.Write(item);
Console.Write(",");
}
}
}
[CompilerGenerated]
internal sealed class <PrivateImplementationDetails>
{
// Token: 0x0600002B RID: 43 RVA: 0x00002999 File Offset: 0x00000B99
internal static ReadOnlySpan<TElement> InlineArrayAsReadOnlySpan<TBuffer, TElement>(in TBuffer buffer, int length)
{
return MemoryMarshal.CreateReadOnlySpan<TElement>(Unsafe.As<TBuffer, TElement>(Unsafe.AsRef<TBuffer>(ref buffer)), length);
}
// Token: 0x0600002C RID: 44 RVA: 0x000029AC File Offset: 0x00000BAC
internal static Span<TElement> InlineArrayAsSpan<TBuffer, TElement>(ref TBuffer buffer, int length)
{
return MemoryMarshal.CreateSpan<TElement>(Unsafe.As<TBuffer, TElement>(ref buffer), length);
}
// Token: 0x0600002D RID: 45 RVA: 0x000029BA File Offset: 0x00000BBA
internal static ref TElement InlineArrayElementRef<TBuffer, TElement>(ref TBuffer buffer, int index)
{
return Unsafe.Add<TElement>(Unsafe.As<TBuffer, TElement>(ref buffer), index);
}
// Token: 0x04000009 RID: 9 RVA: 0x000058A8 File Offset: 0x00003AA8
internal static readonly <PrivateImplementationDetails>.__StaticArrayInitTypeSize=12 4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D;
// Token: 0x0400000A RID: 10 RVA: 0x000058B8 File Offset: 0x00003AB8
internal static readonly <PrivateImplementationDetails>.__StaticArrayInitTypeSize=12_Align=4 4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D4;
// Token: 0x0400000B RID: 11 RVA: 0x000058C8 File Offset: 0x00003AC8
internal static readonly <PrivateImplementationDetails>.__StaticArrayInitTypeSize=12 8CA6EE1043DEFCFD05AA29DEE581CBC519E783E414A687D7C26AC6070D3F6DEE;
// Token: 0x0400000C RID: 12 RVA: 0x000058D8 File Offset: 0x00003AD8
internal static readonly <PrivateImplementationDetails>.__StaticArrayInitTypeSize=12 BCBC01A5036673E493422616677A83718EDFE475D3E938B1A879903FFB2A05A0;
// Token: 0x0200001B RID: 27
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 12)]
private struct __StaticArrayInitTypeSize=12
{
}
// Token: 0x0200001C RID: 28
[StructLayout(LayoutKind.Explicit, Pack = 4, Size = 12)]
private struct __StaticArrayInitTypeSize=12_Align=4
{
}
}
References
https://github.com/WeihanLi/SamplesInPractice/blob/master/CSharp12Sample/InlineArraySample.cs
https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/inline-arrays.md
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/unsafe-code#fixed-size-buffers
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-12#inline-arrays
-
技术群:添加小编微信并备注进群
小编微信:mm1552923
公众号:dotNet编程大全