目前,我有这段代码:
class SO
{
public SO()
{
var ptrManager = new PointerManager();
int i = 1;
ptrManager.SavePointer(ref i);
Console.WriteLine(i); // prints 1
i = 2; //change value to 2 within the current scope
Console.WriteLine(i); // prints 2
ptrManager.SetValue(3); // change value to 3 in another (unsafe) scope
Console.WriteLine(i); // prints 3
}
}
unsafe class PointerManager
{
private int* ptr;
public void SavePointer(ref int i)
{
fixed (int* p = &i)
{
ptr = p;
}
}
public void SetValue(int i)
{
*ptr = i;
}
}
首先,我告诉PointerManager
创建一个指向我的int i
的指针。
这样,稍后,我就可以告诉PointerManager
更改i
的值,而无需再次传递i
。
到目前为止,这似乎运作良好。但是,我已经读过,如果GC决定在内存中移动i
,那么我的指针ptr
将变为无效,随后对SetValue
的调用将具有不可预测的行为。
那么,如何阻止GC移动i
? 或,或者,是否有更好的方法来实现我的目标?
我也被告知只需添加GCHandle.Alloc(i, GCHandleType.Pinned);
即可,但这似乎不正确......
修改:更具体地说,我会在GCHandle.Alloc
方法的开头调用SavePointer
。
答案 0 :(得分:1)
您可以使用Function和Action类型的强大功能来实现相同功能,而不会出现任何不安全的代码。尽量避免任何不安全的ocde或指针,如果你没有与非托管代码连接,你不需要它们:
using System;
namespace ConsoleApplication16
{
class SO
{
public static void Main()
{
var manager = new LateSetter<int>();
int i = 1;
manager.SaveSetter(newValue => i = newValue);
Console.WriteLine(i); // prints 1
i = 2;
Console.WriteLine(i); // prints 2
manager.SetValue(3); // change value to 3
Console.WriteLine(i); // prints 3
Console.ReadLine();
}
}
class LateSetter<T>
{
private Action<T> set;
public void SaveSetter(Action<T> setter)
{
this.set = setter;
}
public void SetValue(T i)
{
this.set(i);
}
}
}
答案 1 :(得分:1)
通常你不想阻止GC移动任何东西 - 特别是在你的情况下(事务对象),我宁愿考虑这样的选项:
第二个选项解释:
class VariableManager
{
private Action<int> setter;
public void VariableManager(Action<int> setter)
{
this.setter = setter;
}
public void SetValue(int i)
{
setter(i);
}
}
只需通过new VariableManager(i => yourInt = i)
和中提琴创建经理 - 您就可以在没有指针的情况下获得所需的语义!