Okay, I've found that it actually is possible with pointers if in unsafe context:
public static class IntEx {
unsafe public static Action CreateIncrementer(int* reference) {
return () => {
*reference += 1;
};
}
}
However, the garbage collector can wreak havoc with this by moving your reference during garbage collection, as the following indicates:
class Program {
static void Main() {
new Program().Run();
Console.ReadLine();
}
int _i = 0;
public unsafe void Run() {
Action incr;
fixed (int* p_i = &_i) {
incr = IntEx.CreateIncrementer(p_i);
}
incr();
Console.WriteLine(_i); // Yay, incremented to 1!
GC.Collect();
incr();
Console.WriteLine(_i); // Uh-oh, still 1!
}
}
One can get around this problem by pinning the variable to a specific spot in memory. This can be done by adding the following to the constructor:
public Program() {
GCHandle.Alloc(_i, GCHandleType.Pinned);
}
That keeps the garbage collector from moving the object around, so exactly what we're looking for. However then you've got to add a destructor to release the pin, and it fragments the memory throughout the lifetime of the object. Not really any easier. This would make more sense in C++, where stuff doesn't get moved around, and resource management is par the course, but not so much in C# where all that is supposed to be automatic.
So looks like the moral of the story is, just wrap that member int in a reference type and be done with it.
(And yes, that's the way I had it working before asking the question, but was just trying to figure out if there was a way I could get rid of all my Reference<int> member variables and just use regular ints. Oh well.)
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…