C#指针和值类型变量的重新定位

C#指针和值类型变量的重新定位,c#,.net,visual-studio-2015,unsafe,C#,.net,Visual Studio 2015,Unsafe,我编写了以下不安全类,它将指针包装为int: unsafe class PtrWrapper { public PtrWrapper(ref int val) { fixed (int* ptr = &val) { m_ptr = ptr; } } public int Value { get { return *m_ptr; } set { *m_ptr = val

我编写了以下不安全类,它将指针包装为int:

unsafe class PtrWrapper
{
   public PtrWrapper(ref int val)
   {
       fixed (int* ptr = &val)
       {
           m_ptr = ptr;
       }
   }
   public int Value
   {
       get { return *m_ptr; }
       set { *m_ptr = value; }
   }
   int * m_ptr;
}
我已经对它进行了测试,它似乎工作得很好,但是我刚刚再次阅读了on fixed,看起来指针上的所有操作都应该在语句中完成:

如果没有固定,指向可移动托管变量的指针将是无效的 因为垃圾收集可以重新定位变量,所以没有什么用处 无法预测


那么,当我调用Value属性时,指针对象是否可能在内存中重新定位,而我的指针指向其他对象?我知道如果指针对象超出范围,我会遇到问题,但我会通过如何使用我的类来解释。因此,我想重新定位一个尚未超出范围的值类型变量。

是的,这是非常可能的,甚至是可能的

在堆上:

class M 
{
    public int i;
    public PtrWrapper w;

    public M()
    {
        i = 42;
        w = new PtrWrapper(ref i);
    }
}

var m = new M();
var value = m.w.Value; // probably 42

// move m to gen 2
GC.Collect();
GC.Collect();

value = m.w.Value; // probably a random value
这就是为什么它被称为不安全:)
fixed
只会在范围内阻止某些东西移动

在堆栈上,但它应该是好的。只有在超出范围时,才会弹出堆栈上的变量,例如在本例中:

PtrWrapper M()
{
    var i = 42;
    var w = new PtrWrapper(ref i);
    return w;
}

var w = M();
var value = w.Value; // some random value

请注意,捕获的变量(在lambdas中)确实在堆上,因此在该场景中应小心使用这些变量。

嗨,Eli,我多次尝试了第一个示例,但它总是给出相同的结果。运行时是否得到了随机值?我注意到这个答案是在2016年发布的,您可能使用的是旧的.Net框架。我不确定是不是这个原因。