Хорошо, я обнаружил, что на самом деле возможно с указателями, если в небезопасном контексте:
public static class IntEx {
unsafe public static Action CreateIncrementer(int* reference) {
return () => {
*reference += 1;
};
}
}
Однако сборщик мусора может нанести ущерб этому, переместив вашу ссылку во время сбора мусора, как показано ниже:
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!
}
}
Эту проблему можно обойти, закрепив переменную в определенном месте в памяти. Это можно сделать, добавив в конструктор следующее:
public Program() {
GCHandle.Alloc(_i, GCHandleType.Pinned);
}
Это мешает сборщику мусора перемещать объект, именно то, что мы ищем. Однако затем вы должны добавить деструктор, чтобы освободить булавку, и он фрагментирует память в течение всего срока службы объекта. Не намного проще. Это имело бы больше смысла в C ++, где вещи не перемещаются, а управление ресурсами - само собой разумеется, но не так много в C #, где все это должно быть автоматическим.
Похоже, что мораль этой истории такова, просто оберните этот элемент int в ссылочный тип и покончите с этим.
(И да, я так и работал, прежде чем задавать вопрос, но просто пытался выяснить, можно ли как-нибудь избавиться от всех моих переменных-членов Reference и просто использовать обычные целые числа. Ну хорошо.)