Вот очень упрощенная версия того, что я пытаюсь сделать
static void Main(string[] args)
{
int test = 0;
int test2 = 0;
Test A = new Test(ref test);
Test B = new Test(ref test);
Test C = new Test(ref test2);
A.write(); //Writes 1 should write 1
B.write(); //Writes 1 should write 2
C.write(); //Writes 1 should write 1
Console.ReadLine();
}
class Test
{
int _a;
public Test(ref int a)
{
_a = a; //I loose the reference here
}
public void write()
{
var b = System.Threading.Interlocked.Increment(ref _a);
Console.WriteLine(b);
}
}
В моем реальном коде у меня есть интервал, который будет увеличен многими потоками однако, где потоки названный, не будет легко передать его параметр, который указывает на него на интервал (В реальном коде это происходит внутри a IEnumerator
). Таким образом, требование является ссылкой, должен быть сделан в конструкторе. Также не все потоки будут указывать на тот же единственный основной интервал, таким образом, я не смогу использовать глобальный статический интервал также. Я знаю, что могу просто упаковать интервал в классе и раздать класс, но я хотел знать - ли это корректный способ сделать что-то вроде этого?
То, что я думаю, могло быть корректным путем:
static void Main(string[] args)
{
Holder holder = new Holder(0);
Holder holder2 = new Holder(0);
Test A = new Test(holder);
Test B = new Test(holder);
Test C = new Test(holder2);
A.write(); //Writes 1 should write 1
B.write(); //Writes 2 should write 2
C.write(); //Writes 1 should write 1
Console.ReadLine();
}
class Holder
{
public Holder(int i)
{
num = i;
}
public int num;
}
class Test
{
Holder _holder;
public Test(Holder holder)
{
_holder = holder;
}
public void write()
{
var b = System.Threading.Interlocked.Increment(ref _holder.num);
Console.WriteLine(b);
}
}
Существует ли лучший путь, чем это?
По сути, ответ - да, вам нужен класс.
Не существует концепции «ссылки на int», которую можно было бы сохранить как поле. В C # это ограничено параметрами.
И хотя существует небезопасный
способ (указатель на int, int *
), сложности работы с GC в этом сценарии делают его непрактичным и неэффективным.
Итак, ваш второй пример выглядит нормально.
Вы не можете хранить ссылку на переменную именно по той причине, что кто-то может сделать то, что вы делаете: взять ссылку на локальную переменную, а затем использовать эту ссылку после того, как хранение локальной переменной будет восстановлено.
Ваш подход к превращению переменной в поле класса вполне подходит. Альтернативный способ сделать то же самое - создать делегаты getter и setter для переменной. Если делегаты замкнуты на внешнюю локальную переменную, то эта внешняя локальная будет поднята в поле, так что ее время жизни будет больше, чем у делегатов.
Невозможно сохранить ссылку как поле.
Вам нужно сохранить int в классе.