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

使用out参数时C#编译器抛出无关ref返回错误求助

C#按引用返回时的编译器错误

错误提示

无法按引用返回“entity”,因为它被初始化为无法按引用返回的值

问题代码

我实现了一个数组包装类UnorderedSegmentedList,核心代码如下:

public sealed class UnorderedSegmentedList<TValue> : ISegmentedList where TValue : struct
{
    private readonly int _arraySize;
    private List<Array> _arrayList = new List<Array>();
    public int ReservedValuesCount { get; private set; }

    public ref TValue Reserve(out int index)
    {
        var targetIndex = ReservedValuesCount;
        ReservedValuesCount++;
        var indices = CalculateIndices(targetIndex);
        var array = GetArray(indices.arrayIndex);
        index = indices.localItemIndex;
        return ref array[indices.localItemIndex];
    }

    private (int arrayIndex, int localItemIndex) CalculateIndices(int index)
    {
        return (index / _arraySize, index % _arraySize);
    }

    private TValue[] GetArray(int arrayIndex)
    {
        return (TValue[])_arrayList[arrayIndex];
    }
}

当我将该类用于值类型Entity并尝试按引用返回时触发错误,使用代码如下:

public struct Entity
{
    public readonly int Id;
}

public class Container
{
    private readonly UnorderedSegmentedList<Entity> _entities;

    public ref Entity CreateEntity()
    {
        ref var entity = ref _entities.Reserve(out var index);
        entity = new Entity(index, _componentsContainer, new List<ComponentKey>());
        return ref entity;
    }
}

移除所有out int index参数后代码可正常运行,但我无法理解这个变量和struct的关联,这是编译器bug吗?


解答

这不是编译器bug,是C#引用返回的静态分析规则导致的限制。

原因分析

C#对引用返回的存储位置有严格的生命周期要求:返回的引用必须指向长期存在的存储位置(比如类的字段、数组元素等)。当调用带有out参数的方法时,编译器会增强静态分析逻辑——它无法确定Reserve方法的返回引用是否与out参数存在隐式依赖(比如out参数的赋值是否会间接影响返回引用的有效性),因此会判定当前获取的引用生命周期不足以支持后续的返回操作。

解决方法

  • 方法1:拆分out变量声明与引用赋值
    先显式声明index变量,再调用方法,让编译器明确识别引用的独立性:

    public ref Entity CreateEntity()
    {
        int index;
        ref var entity = ref _entities.Reserve(out index);
        entity = new Entity(index, _componentsContainer, new List<ComponentKey>());
        return ref entity;
    }
    
  • 方法2:调整Reserve方法的返回形式
    可以将索引和引用的返回拆分,比如先获取索引再获取引用,或者改用返回包含索引的自定义结构体(注意元组无法直接存储引用类型),避免out参数与引用返回的冲突。

补充说明

当你移除out参数后,编译器能直接确认返回的引用指向数组元素(属于长期存在的存储),因此不会触发错误。这种严格的检查是为了避免引用悬空等内存安全问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 19:17:44