在 C# 中,为什么不能使用局部变量的地址填充该变量,然后再使用该变量?

Gri*_*ios 6 c# lambda local-variables memory-address

考虑以下代码:

private unsafe void Function()
{
    int length;

    // This line raises error CS1686, "Local 'length' or its members cannot have their address taken and be used inside an anonymous method or lambda expression".
    glGetProgramiv(1, GL_PROGRAM_BINARY_LENGTH, &length);

    FunctionWithLambda(() => Console.WriteLine(length));
}

private void FunctionWithLambda(Action callback)
{
    callback();
}
Run Code Online (Sandbox Code Playgroud)

length请注意,我获取(局部变量)的地址,然后在 lambda 中使用该变量本身而不是其地址)。我理解为什么局部变量地址不能直接在 lambda 中使用(参见为什么不能将变量的地址传递给匿名函数?等示例),但是为什么我不能使用一次分配的length(即使该赋值碰巧使用了&运算符)?错误 CS1686 的官方文档(https://learn.microsoft.com/bs-latn-ba/dotnet/csharp/misc/cs1686)尚未澄清这种混乱。

我的假设是,这只是一种语言限制,但我很好奇是否有我遗漏的潜在技术原因。另请注意,我不是问如何解决这个问题(我知道我可以length先轻松复制到另一个局部变量)。

Cha*_*ace 1

C# 规范规定如下 (我的粗体)

\n
\n

23.4 固定变量和可移动变量

\n

地址运算符(\xc2\xa723.6.5) 和fixed语句 (\xc2\xa723.7) 将变量分为两类:
\n固定变量可移动变量

\n

...剪断...

\n

运算&符(\xc2\xa723.6.5)允许不受限制地获取固定变量的地址。但是,由于可移动变量会被垃圾收集器重定位或处置,因此只能使用fixed语句(\xc2\xa723.7) 来获取可移动变量的地址,并且该地址仅在该语句的持续时间内保持有效。fixed陈述。

\n

准确地说,固定变量是以下之一:

\n
    \n
  • 由引用局部变量、值参数或参数数组的简单名称 (\xc2\xa712.7.3) 生成的变量,除非该变量由匿名函数 (\xc2\xa712.16.6.2) 捕获
  • \n
  • ……
  • \n
\n
\n

所以它是规范明确禁止的。至于为什么禁止它,你必须询问语言设计者,但考虑到捕获变量涉及多少复杂性,这在某种程度上是合乎逻辑的。

\n