“无法在 lambda 表达式中使用固定局部”

发布于 2024-09-01 04:24:39 字数 917 浏览 4 评论 0原文

我有一个 XNA 3.0 项目,在 VS2008 中编译得很好,但在 VS2010 中(使用 XNA 4.0 CTP)会出现编译错误。错误:

无法在匿名方法、lambda 表达式或查询表达式中使用固定的本地“深度Ptr”

depthPtr 是数组中的固定 float*,在 内部使用来自 System.Threading 的 Parallel.For lambda 表达式。正如我所说,它在 VS2008 上编译并运行得很好,但在 VS2010 上则不然,即使针对 .NET 3.5 也是如此。

这在 .NET 4.0 中发生了变化吗?即使如此,当我选择 .NET 3.5 作为目标框架时,它不应该仍然可以编译吗?在 Google 和 Bing 中搜索术语“无法使用固定本地”只会产生一个(无用)结果。

如果情况发生了变化,那么原因是什么?我可以想象在闭包中捕获固定指针类型可能会有点奇怪,这是为什么吗?所以我猜这是不好的做法?在有人问之前:不,指针的使用在这里并不是绝对重要的。不过我还是想知道:)

编辑: 根据要求,一个代码示例(显然不是来自我的程序)重现了错误:

static unsafe void Main(string[] args)
{
  float[] array = new float[10];

  fixed (float* ptr = array)
  {
    Parallel.For(0, 10, i =>
    {
      ptr[i] = i;
    });
  }
}

上面的代码在 VS2008 中编译(好吧,除了对 Parallel 的引用之外,任何其他 lambda 表达式都可以),但在VS2010中没有。

I have an XNA 3.0 project that compiled just fine in VS2008, but that gives compile errors in VS2010 (with XNA 4.0 CTP). The error:

Cannot use fixed local 'depthPtr' inside an anonymous method, lambda expression, or query expression

depthPtr is a fixed float* into an array, that is used inside a Parallel.For lambda expression from System.Threading. As I said, this compiled and ran just fine on VS2008, but it does not on VS2010, even when targeting .NET 3.5.

Has this changed in .NET 4.0, and even so, shouldn't it still compile when I choose .NET 3.5 as the target framework? Searching for the term "Cannot use fixed local" yields exactly one (useless) result, both in Google and Bing.

If this has changed, what is the reason for this? I can imagine capturing a fixed pointer-type in a closure could get a bit weird, is that why? So I'm guessing this is bad practice? And before anyone asks: no, the use of pointers is not absolutely critical here. I would still like to know though :)

EDIT:
As requested, a code sample (not from my program, obviously) that reproduces the error:

static unsafe void Main(string[] args)
{
  float[] array = new float[10];

  fixed (float* ptr = array)
  {
    Parallel.For(0, 10, i =>
    {
      ptr[i] = i;
    });
  }
}

The above compiles in VS2008 (well, aside from the reference to Parallel, but any other lambda expression will do), but does not in VS2010.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

相对绾红妆 2024-09-08 04:24:39

固定在块的持续时间内固定一个指针。如果您要存储委托以供稍后在块退出后调用,则垃圾收集器可能会在创建 lambda 和调用 lambda 之间移动对象。至于为什么针对不同的框架没有帮助,这是因为这是由语言/编译器而不是运行时强制执行的(如果是运行时,它将在运行时通过异常或类似的方式报告,而不是由运行时报告)编译时的编译器)。

fixed pins a pointer for the duration of the block. If you were to store the delegate to invoke later after the block had been exited the garbage collector could move the object between when the lambda is created and when the lambda is invoked. As to why targeting a different framework doesn't help, this is because this is being enforced by the language/compiler, not the runtime (if it were the runtime, it would be reported via an exception or similar at runtime, not by the compiler at compile time).

德意的啸 2024-09-08 04:24:39

这有效。基本上,我们消除了包含不安全指针的 lambda,并将其替换为在 fixed 块内声明的类实例的委托。

    static unsafe void UnsafeTest(string[] args) {
        float[] array = new float[10];

        fixed(float* ptr = array) {
            UnsafeOps ops = new UnsafeOps();
            ops.p = ptr;

            Parallel.For(0, 10, ops.Lambda);
        }
    }

    unsafe class UnsafeOps {
        public float* p;
        public unsafe void Lambda(int value) {
            p[value] = value;
        }
    }

在我看来,.NET 4 添加了一些半途而废的尝试,禁止编译器中的固定内存访问。在上面的代码块中,您可以在 fixed 块外部定义 UnsafeOps 并在 fixed 块之后访问数组。所以它并不完美...

This works. Basically we eliminated the lambda containing an unsafe pointer and replaced it with a delegate to an instance of a class declared inside the fixed block.

    static unsafe void UnsafeTest(string[] args) {
        float[] array = new float[10];

        fixed(float* ptr = array) {
            UnsafeOps ops = new UnsafeOps();
            ops.p = ptr;

            Parallel.For(0, 10, ops.Lambda);
        }
    }

    unsafe class UnsafeOps {
        public float* p;
        public unsafe void Lambda(int value) {
            p[value] = value;
        }
    }

Looks to me like .NET 4 added some half-arsed attempt at disallowing fixed memory access in the compiler. In the above code block you could define UnsafeOps outside the fixed block and access the array after the fixed block. So it's not perfect...

萌化 2024-09-08 04:24:39

doco 说你不是允许在匿名方法中访问不安全的代码,并且相同的限制适用于 lambda,所以我认为这可能是你的问题。你有实际的编译器错误吗?

The doco say you are not allowed to access unsafe code in an anonymous methods, and the same restrictions apply to lambdas, so I think that may be your problem. Do you have the actual compiler error no?

忘你却要生生世世 2024-09-08 04:24:39

编译器拒绝该代码是正确的。固定只能用于局部变量,并且闭包捕获的变量不是局部变量,它们被提升到用于维护闭包状态的类中。

The compiler is correct to reject that code. Fixed can only be used on local variables, and variables captured by a closure are not local variables, they are hoisted into the class used to maintain state for the closure.

樱花坊 2024-09-08 04:24:39

一种解释可能是,变量的值是在执行闭包时获取的,而不是在定义时获取的。在您的示例中,它可能不会造成任何伤害,但在其他情况下可能会造成任何伤害。因此,为了教授良好的实践,完全禁止防止各种有趣的错误。

One explanation could be, that the value of a variable is taken at the execution of the closure, not the definition. In your example it probably wouldn't do any harm, but in other cases it could be. So to teach good practise, it is forbidden altogether to prevent all kinds of interesting bugs.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文