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

C#如何在类中存储struct的ref引用?WPF客户端信息编辑场景问题

C# 不允许将ref引用存储到类的属性或字段中,本质是ref引用的生命周期被限制为仅在当前方法调用栈内有效,而类是堆上对象,生命周期可能长于栈上的struct实例,强制存储会引发内存安全风险。以下是几种可行的实现方案:

方案1:将值类型struct改为引用类型class(最推荐,无额外复杂度)

如果没有必须使用struct的硬性要求,直接修改ClientInfos的定义为class即可,引用类型天然支持在类中存储实例引用:

// 修改为class
public class ClientInfos
{
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public int Age { get; set; }
}

对应的调用和ViewModel代码同步简化,无需ref传递:

// 窗口调用
ClientInfosWindow.Show(clientInfos);

// ViewModel实现
class ClientInfosViewModel
{
    private readonly ClientInfos _originalClientInfos;
    public ClientInfos ClientInfosTemp { get; set; }

    public ClientInfosViewModel(ClientInfos clientInfos)
    {
        _originalClientInfos = clientInfos;
        // 拷贝初始值到临时对象
        ClientInfosTemp = new ClientInfos
        {
            Firstname = clientInfos.Firstname,
            Lastname = clientInfos.Lastname,
            Age = clientInfos.Age
        };
    }

    private void SaveClientInfos()
    {
        // 同步临时值到原始实例
        _originalClientInfos.Firstname = ClientInfosTemp.Firstname;
        _originalClientInfos.Lastname = ClientInfosTemp.Lastname;
        _originalClientInfos.Age = ClientInfosTemp.Age;
        ClientInfosWindow.Close();
    }
}
方案2:使用引用类型包装struct(适合必须保留struct的场景)

如果确实需要保留ClientInfos为struct,可以封装一个泛型引用类型包装类承载struct值:

// 通用值类型包装类
public class ValueWrapper<T> where T : struct
{
    public T Value { get; set; }
    public ValueWrapper(T value) => Value = value;
}

调用时传递包装类实例:

// 外层定义包装实例
var clientWrapper = new ValueWrapper<ClientInfos>(clientInfos);
ClientInfosWindow.Show(clientWrapper);

ViewModel中存储包装类引用即可:

class ClientInfosViewModel
{
    private readonly ValueWrapper<ClientInfos> _originalWrapper;
    public ClientInfos ClientInfosTemp { get; set; }

    public ClientInfosViewModel(ValueWrapper<ClientInfos> wrapper)
    {
        _originalWrapper = wrapper;
        ClientInfosTemp = wrapper.Value;
    }

    private void SaveClientInfos()
    {
        _originalWrapper.Value = ClientInfosTemp;
        ClientInfosWindow.Close();
    }
}
// 外层使用时取clientWrapper.Value即为更新后的值
方案3:使用回调委托回传结果(解耦性最优,符合MVVM设计规范)

不需要在ViewModel中存储原始实例引用,通过委托将更新后的值回传给调用方:

// 窗口调用时传入回调
ClientInfosWindow.Show(clientInfos, updatedInfos => {
    clientInfos = updatedInfos;
});

ViewModel实现:

class ClientInfosViewModel
{
    private readonly Action<ClientInfos> _saveCallback;
    public ClientInfos ClientInfosTemp { get; set; }

    public ClientInfosViewModel(ClientInfos originalInfos, Action<ClientInfos> saveCallback)
    {
        _saveCallback = saveCallback;
        ClientInfosTemp = originalInfos;
    }

    private void SaveClientInfos()
    {
        _saveCallback?.Invoke(ClientInfosTemp);
        ClientInfosWindow.Close();
    }
}
不推荐方案:unsafe指针

如果一定要操作原始struct的内存地址,可以开启unsafe上下文用指针存储,但会引入内存安全风险,不建议在业务代码中使用:

unsafe class ClientInfosViewModel
{
    private ClientInfos* _originalPtr;
    public ClientInfos ClientInfosTemp { get; set; }

    public unsafe ClientInfosViewModel(ref ClientInfos clientInfos)
    {
        fixed (ClientInfos* ptr = &clientInfos)
        {
            _originalPtr = ptr;
        }
        ClientInfosTemp = clientInfos;
    }

    private unsafe void SaveClientInfos()
    {
        *_originalPtr = ClientInfosTemp;
        ClientInfosWindow.Close();
    }
}

内容的提问来源于stack exchange,提问作者Maxime Charrière

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 02:27:03