惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Security @ Cisco Blogs
P
Privacy & Cybersecurity Law Blog
P
Privacy International News Feed
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Threatpost
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Project Zero
Project Zero
C
CERT Recently Published Vulnerability Notes
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
C
Cisco Blogs
博客园 - 司徒正美
L
LINUX DO - 热门话题
D
Docker
M
MIT News - Artificial intelligence
GbyAI
GbyAI
Microsoft Azure Blog
Microsoft Azure Blog
Microsoft Security Blog
Microsoft Security Blog
Cisco Talos Blog
Cisco Talos Blog
Jina AI
Jina AI
Last Week in AI
Last Week in AI
Security Latest
Security Latest
The Hacker News
The Hacker News
L
Lohrmann on Cybersecurity
Y
Y Combinator Blog
A
Arctic Wolf
小众软件
小众软件
T
Threat Research - Cisco Blogs
Know Your Adversary
Know Your Adversary
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
I
InfoQ
腾讯CDC
Google DeepMind News
Google DeepMind News
B
Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - 叶小钗
I
Intezer
NISL@THU
NISL@THU
A
About on SuperTechFans
爱范儿
爱范儿
C
Cybersecurity and Infrastructure Security Agency CISA
D
Darknet – Hacking Tools, Hacker News & Cyber Security
G
Google Developers Blog
J
Java Code Geeks
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Cyberwarzone
Cyberwarzone
AWS News Blog
AWS News Blog
Engineering at Meta
Engineering at Meta
Latest news
Latest news

博客园 - Charltsing

C# 预处理器指令语言 - 完整语法速查 LoggerMessage:编写高性能的 .NET 日志 PDFImageViewer v2.1 PDF查看图像和无损导出工具,一键转换单图PDF为JBig2黑白PDF。兼谈PDF内嵌图像。 PDF的色彩空间 25 个使用.NET 10 的性能技巧 PDFontFixer v1.5 免费版,解决PDF文档复制粘贴乱码的问题,修复PDF文档字体的Unicode映射。 为什么 PDF 编辑这么难? Unicode、UTF-8、UTF-16 如何直接编辑Github的Readme.md文件 自动导入工程项目属性,Directory.Build.props 和 Directory.Build.targets 新版 C# 高效率编程指南 如何在 .NET 中使用 SIMD .NET异步编程进阶:从语法糖到高性能架构的核心突破 C# 中的安全零拷贝 使用UnsafeAccessor 访问私有字段 C# 12与.NET 8实战指南:20个提升代码质量的最佳实践 C# Net9的模块初始化器(Module Initializer) ECMA-335 CLI 规范附录 C#中避免GC压力和提高性能的8种技术 函数内联 硬件内在函数 官方:oPDF v2.1免费版,专业的PDF水印分析处理工具,无损去除水印,通杀八类PDF水印。它是PDFCommander 万能PDF水印删除工具的升级版。 C#自动引用Debug | Release版本的dll
C# 内联数组(Inline Array):高性能数组的新选择
Charltsing · 2026-01-10 · via 博客园 - Charltsing

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; // 单一字段,表示数组的起点
}
  • Size:一个编译时常量,表示数组的固定长度。
  • T:数组元素的类型(可以是值类型或引用类型)。
  • 单一字段:结构体中只能有一个字段,表示数组的起点,编译器会将其扩展为固定大小的连续内存。
[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)
  •  Vector3D 模拟一个三维向量,内联数组确保内存连续。
  • 适合游戏开发或科学计算。

与本机代码交互
内联数组的连续内存布局使其非常适合与本机代码(如 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);
  • CharBuffer 的内存布局与 C 语言中的 char[8] 兼容。
  • 通过 ref 传递,确保本机代码可以直接操作内存。

高级用法
与不安全代码结合

[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[] 字段,减少堆分配。
向量/矩阵操作:表示数学向量或矩阵,优化内存访问。


注意事项
仅限结构体:

  • 只能定义在 struct 中,不能用于 class。
  • 这是因为结构体是值类型,内存分配更可控。

固定大小:

  • 内联数组的大小在编译时必须是常量,无法动态调整。
  • 不适合需要变长数组的场景。

单一字段限制:

  • 带有 [InlineArray] 的结构体只能包含一个字段。
  • 如果需要其他字段,必须使用嵌套结构体。
[InlineArray(10)]
struct InvalidBuffer
{
    private int _element;
    private int _otherField; // 错误:只能有一个字段
}

性能优势:

  • 内联数组分配在栈上(对于局部变量)或嵌入结构体中,减少堆分配。
  • 连续内存布局减少缓存未命中(cache miss),提高性能。

版本要求:

  • 内联数组是 C# 12(.NET 8)的新特性,需确保项目目标框架为 .NET 8.0 或更高。
  • 需要 System.Runtime.CompilerServices.InlineArray 特性。

索引越界:

  • 内联数组支持索引访问,但不会自动检查越界。
  • 使用 Span<T> 操作时,Span<T> 会提供边界检查。 
[InlineArray(2)]
struct SmallBuffer
{
    private int _element;
}

var buffer = new SmallBuffer();
buffer[2] = 1; // 运行时异常:索引越界

与普通数组的对比:

  • 普通数组(T[]):分配在托管堆上,动态大小,支持垃圾回收。
  • 内联数组:固定大小,嵌入结构体,连续内存,适合高性能场景。

与其他特性的对比
与普通数组(T[])的对比:

  • 普通数组是引用类型,分配在堆上,大小可动态调整。
  • 内联数组是值类型的一部分,固定大小,内存连续,性能更高。

与固定大小缓冲区(fixed)的对比:

  • C# 的 fixed 关键字用于在 unsafe 上下文中创建固定大小缓冲区。
  • 内联数组是类型安全的,无需 unsafe,更易用。

与 Span<T>/Memory<T> 的对比:

  • 内联数组是数据的存储结构,而 Span<T>和Memory<T>是访问视图。
  • 内联数组可直接转换为 Span<T>,结合使用效率更高。

与栈分配(stackalloc)的对比:

  • stackalloc 在栈上分配临时内存,生命周期短。
  • 内联数组嵌入结构体,支持更灵活的生命周期和传递。