You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#类成员变量中持有struct的引用?

在C#中持有外部struct引用的等效实现

你的核心需求是让C#类持有外部框架创建的struct的引用(而非拷贝),以便能访问到该struct的动态更新内容。由于C#中struct是值类型,默认操作会产生拷贝,以下是几种符合需求的实现方式:

1. 不安全代码直接使用指针(最贴近C++逻辑)

这种方式和你的C++代码逻辑几乎一致,需要在项目中开启允许不安全代码编译选项(项目属性→生成→勾选对应选项)。

代码示例

// 外部框架定义的不可修改struct
public struct sMyStruct
{
    public int SomeValue;
    // 其他字段...
}

public class MyClass
{
    // 持有struct的指针
    private unsafe sMyStruct* _refToStruct;

    // 构造函数接收指针
    public unsafe MyClass(sMyStruct* refToStruct)
    {
        _refToStruct = refToStruct;
    }

    // 访问并修改原struct内容的示例方法
    public unsafe void UpdateStructValue(int newValue)
    {
        if (_refToStruct != null)
        {
            _refToStruct->SomeValue = newValue;
        }
    }
}

// 使用示例
unsafe class Program
{
    static void Main()
    {
        // 模拟外部框架创建的非托管struct
        unsafe
        {
            sMyStruct* myStruct = (sMyStruct*)Marshal.AllocHGlobal(sizeof(sMyStruct));
            myStruct->SomeValue = 10;

            MyClass c = new MyClass(myStruct);
            c.UpdateStructValue(20);
            // 此时原struct的SomeValue已变为20

            // 内存释放由外部框架负责,此处仅为示例
            Marshal.FreeHGlobal((IntPtr)myStruct);
        }
    }
}

注意事项

  • 必须确保外部struct的内存生命周期由框架或你正确管理,避免野指针问题。
  • 仅限 blittable 类型的struct(可直接在托管/非托管内存间转换)使用。

2. 使用Memory<T>/Span<T>(安全的托管内存引用)

Span<T>是栈分配的内存引用类型,无法直接作为类字段存储;Memory<T>是堆兼容的内存包装类型,可长期持有,需要时转换为Span<T>访问内容,全程无需unsafe代码。

代码示例

public struct sMyStruct
{
    public int SomeValue;
}

public class MyClass
{
    // 用Memory<T>长期持有内存引用
    private Memory<sMyStruct> _structMemory;

    public MyClass(Memory<sMyStruct> structMemory)
    {
        _structMemory = structMemory;
    }

    public void UpdateStructValue(int newValue)
    {
        // 转换为Span<T>访问原内存内容
        Span<sMyStruct> structSpan = _structMemory.Span;
        if (!structSpan.IsEmpty)
        {
            structSpan[0].SomeValue = newValue;
        }
    }
}

// 使用示例
class Program
{
    static void Main()
    {
        // 模拟外部框架提供的托管内存中的struct
        sMyStruct[] externalStructArray = new sMyStruct[1];
        externalStructArray[0].SomeValue = 10;

        // 从数组创建Memory<T>指向目标struct
        Memory<sMyStruct> structMemory = externalStructArray.AsMemory(0, 1);
        MyClass c = new MyClass(structMemory);

        c.UpdateStructValue(20);
        // 原struct的内容已更新
        Console.WriteLine(externalStructArray[0].SomeValue); // 输出20
    }
}

注意事项

  • 适用于托管内存中的struct,若外部框架提供非托管内存,可配合Marshal类创建Memory<T>引用。
  • 由CLR管理内存,类型安全,无野指针风险。

3. 使用IntPtr(非托管内存的通用安全方式)

如果外部框架创建的是非托管内存中的struct,可通过IntPtr保存内存地址,借助Marshal类读写内容,全程无需unsafe代码。

代码示例

public struct sMyStruct
{
    public int SomeValue;
}

public class MyClass
{
    private IntPtr _structPtr;

    public MyClass(IntPtr structPtr)
    {
        _structPtr = structPtr;
    }

    public void UpdateStructValue(int newValue)
    {
        if (_structPtr != IntPtr.Zero)
        {
            // 读取原struct内容
            sMyStruct tempStruct = Marshal.PtrToStructure<sMyStruct>(_structPtr);
            tempStruct.SomeValue = newValue;
            // 将修改后的内容写回原内存
            Marshal.StructureToPtr(tempStruct, _structPtr, false);
        }
    }

    public int GetStructValue()
    {
        return _structPtr != IntPtr.Zero 
            ? Marshal.PtrToStructure<sMyStruct>(_structPtr).SomeValue 
            : default;
    }
}

// 使用示例
class Program
{
    static void Main()
    {
        // 模拟外部框架分配非托管内存并初始化struct
        IntPtr structPtr = Marshal.AllocHGlobal(sizeof(sMyStruct));
        sMyStruct initialStruct = new sMyStruct { SomeValue = 10 };
        Marshal.StructureToPtr(initialStruct, structPtr, false);

        MyClass c = new MyClass(structPtr);
        c.UpdateStructValue(20);
        Console.WriteLine(c.GetStructValue()); // 输出20

        // 内存释放由外部框架负责,此处仅为示例
        Marshal.FreeHGlobal(structPtr);
    }
}

注意事项

  • 每次读写会产生struct拷贝,效率略低于指针或Span方式,但完全安全。
  • 非 blittable 类型的struct需添加[StructLayout]属性指定内存布局。

方案选择建议

  • 追求和C++一致的指针逻辑且能开启unsafe代码:选方案1
  • 托管内存场景下需要安全的长期引用:选方案2
  • 非托管内存场景且不想用unsafe代码:选方案3

内容的提问来源于stack exchange,提问作者user3161924

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 08:28:19