
























C# 内联数组(Inline Array):高性能数组的新选择
内联数组是 C# 12 和 .NET 8 中引入的一个高级特性,它允许开发者创建固定大小的、在栈上分配或内联在结构体中的数组。这个特性主要用于高性能场景,可以避免堆分配和垃圾回收的开销。
性能优势
内联数组的主要优势在于性能:
内联数组 vs 传统数组
特性 内联数组 传统数组
内存位置 栈/包含结构体内存 托管堆
分配开销 无额外分配 需要堆分配
最大长度 受栈空间限制(通常≤1MB) 受GC限制(通常≤2GB)
适用场景 高性能计算/嵌入式开发 通用场景
灵活性 固定长度 动态长度
C#版本要求 ≥ C# 12 (.NET 8+) 所有版本
基本语法
内联数组使用 InlineArray 特性和特定的模式来定义:
using System.Runtime.CompilerServices;
[InlineArray(Size)]
struct InlineArrayStruct
{
private T _element; // 单一字段,表示数组的起点
}
[System.Runtime.CompilerServices.InlineArray(10)]
public struct MyInlineArray
{
private int _element0; // 只需要定义一个字段,实际大小由特性指定
}
创建和使用内联数组
基本定义和使用
using System;
using System.Runtime.CompilerServices;
// 定义包含10个整数的内联数组
[InlineArray(10)]
public struct IntArray10
{
private int _element0;
// 可以添加方法或属性来增强功能
public int Length => 10;
public int Sum()
{
int sum = 0;
for (int i = 0; i < Length; i++)
{
sum += this[i];
}
return sum;
}
}
class Program
{
static void Main()
{
IntArray10 array = new IntArray10();
// 初始化数组
for (int i = 0; i < array.Length; i++)
{
array[i] = i * 2;
}
// 访问元素
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine($"array[{i}] = {array[i]}");
}
Console.WriteLine($"总和: {array.Sum()}");
}
}
与 Span<T> 结合
[InlineArray(5)]
struct FloatBuffer
{
private float _element;
}
var buffer = new FloatBuffer();
buffer[0] = 1.5f;
buffer[1] = 2.5f;
Span<float> span = buffer;
Console.WriteLine(span[0]); // 输出: 1.5
Console.WriteLine(span.Length); // 输出: 5
泛型内联数组
[InlineArray(5)]
public struct GenericArray<T>
{
private T _element0;
public int Length => 5;
public void Initialize(T initialValue)
{
for (int i = 0; i < Length; i++)
{
this[i] = initialValue;
}
}
}
// 使用示例
GenericArray<string> stringArray = new GenericArray<string>();
stringArray.Initialize("default");
在性能敏感场景中使用
内联数组适合需要极致性能的场景,例如处理向量或缓冲区。
[InlineArray(3)]
struct Vector3D
{
private float _element;
}
Vector3D AddVectors(Vector3D a, Vector3D b)
{
var result = new Vector3D();
for (int i = 0; i < 3; i++)
{
result[i] = a[i] + b[i];
}
return result;
}
var v1 = new Vector3D { [0] = 1.0f, [1] = 2.0f, [2] = 3.0f };
var v2 = new Vector3D { [0] = 4.0f, [1] = 5.0f, [2] = 6.0f };
var sum = AddVectors(v1, v2);
Console.WriteLine($"({sum[0]}, {sum[1]}, {sum[2]}"); // 输出: (5, 7, 9)
与本机代码交互
内联数组的连续内存布局使其非常适合与本机代码(如 C/C++ )交互。
using System.Runtime.InteropServices;
[InlineArray(8)]
struct CharBuffer
{
private char _element;
}
[DllImport("someNativeLib.dll")]
extern static void ProcessBuffer(ref CharBuffer buffer);
var buffer = new CharBuffer();
buffer[0] = 'H';
buffer[1] = 'e';
buffer[2] = 'l';
buffer[3] = 'l';
buffer[4] = 'o';
ProcessBuffer(ref buffer);
高级用法
与不安全代码结合
[InlineArray(8)]
public unsafe struct DoubleArray
{
private double _element0;
public fixed int Length => 8;
public double* GetPointer()
{
fixed (double* ptr = &this[0])
{
return ptr;
}
}
}
模拟多维数组
// 使用一维内联数组模拟二维数组
[InlineArray(16)] // 4x4 矩阵
public struct Matrix4x4
{
private float _element0;
public int Rows => 4;
public int Columns => 4;
public float this[int row, int col]
{
get => this[row * Columns + col];
set => this[row * Columns + col] = value;
}
public static Matrix4x4 Identity()
{
var matrix = new Matrix4x4();
for (int i = 0; i < 4; i++)
{
matrix[i, i] = 1.0f;
}
return matrix;
}
}
与 Span 和 Memory 互操作
[InlineArray(100)]
public struct Buffer100
{
private byte _element0;
public int Length => 100;
public Span<byte> AsSpan()
{
return MemoryMarshal.CreateSpan(ref this[0], Length);
}
public ReadOnlySpan<byte> AsReadOnlySpan()
{
return MemoryMarshal.CreateReadOnlySpan(ref this[0], Length);
}
}
底层原理
编译后代码结构
// 原始代码
[InlineArray(5)]
public struct Buffer5 { private int _element; }
// 近似编译结果
public struct Buffer5
{
private int _element0;
private int _element1;
private int _element2;
private int _element3;
private int _element4;
public ref int this[int index]
{
get
{
if ((uint)index >= 5)
throw new IndexOutOfRangeException();
return ref Unsafe.Add(ref _element0, index);
}
}
}
适用场景
高性能计算:游戏引擎、图形处理或科学计算中需要连续内存的场景。
缓冲区管理:处理固定大小的缓冲区,如网络数据包或文件读写。
与本机代码交互:与 C/C++ 或其他本机库交互,传递连续内存块。
替代小型数组:在结构体中替代 T[] 字段,减少堆分配。
向量/矩阵操作:表示数学向量或矩阵,优化内存访问。
注意事项
仅限结构体:
固定大小:
单一字段限制:
[InlineArray(10)]
struct InvalidBuffer
{
private int _element;
private int _otherField; // 错误:只能有一个字段
}
性能优势:
版本要求:
索引越界:
[InlineArray(2)]
struct SmallBuffer
{
private int _element;
}
var buffer = new SmallBuffer();
buffer[2] = 1; // 运行时异常:索引越界
与普通数组的对比:
与其他特性的对比
与普通数组(T[])的对比:
与固定大小缓冲区(fixed)的对比:
与 Span<T>/Memory<T> 的对比:
与栈分配(stackalloc)的对比:
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。