9

根据http://blogs.msdn.com/b/pfxteam/archive/2012/04/12/async-await-faq.aspx,该await关键字在unsafe块内被禁止,仅提及“保留非托管指针所固有的困难”。 ' 对于这些困难是什么,是否有很好的解释?

4

1 回答 1

8

你需要知道的两件基本的事情。一个异步方法被 C# 编译器重写为一个包含状态机的名称难以描述的小类。async 方法的局部变量成为该类的字段。

不安全的代码通常依赖于能够创建指向局部变量的指针。固定语句就是这样,它创建了一个隐藏的局部变量,垃圾收集器可以看到并因此在垃圾收集发生时更新,移动正在修复的数组。创建指向局部变量的指针很好,这些变量不会被垃圾收集器移动。线程的堆栈始终位于虚拟内存地址空间中的固定位置。

把两者联系起来,你就会看到问题,一个局部变量可以变成一个类的字段,当垃圾回收发生时,这个字段的地址确实会改变。突然将不安全的代码变成破坏代码。

演示该问题的代码片段:

class Example {
    int field;
    unsafe void Method() {
        int local = 42;
        int* p = &local;   // fine
        int* q = &field;   // CS0212
    }
}

C# 团队本可以努力仔细分析重写后不安全代码仍然可以使用的情况。但是有些情况是无法修复的,例如fixed语句。一堆工作只会给程序员带来令人失望的消息,通常是出于令人困惑的原因。明智的做法是简单地将不安全的代码声明为禁区。

于 2013-03-03T19:28:03.527 回答