Сохранение ссылки на int - PullRequest
5 голосов
/ 30 мая 2010

Вот очень упрощенная версия того, что я пытаюсь сделать

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);
    }
}

В моем реальном коде у меня есть int, который будет увеличиваться многими потоками, однако там, где вызываемые потоки, будет непросто передать ему параметр, указывающий на int (в реальном коде это происходит внутри IEnumerator). Таким образом, требование - ссылка должна быть сделана в конструкторе. Также не все потоки будут указывать на один и тот же базовый int, поэтому я не могу использовать глобальный static int. Я знаю, что могу просто поместить int внутри класса и передать класс, но я хотел знать, является ли это правильным способом сделать что-то подобное?

То, что я считаю правильным:

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);
    }
}

Есть ли лучший способ, чем этот?

Ответы [ 3 ]

5 голосов
/ 30 мая 2010

По сути, ответ: да, вам нужен класс.

Не существует понятия «ссылка на int», которое вы можете хранить как поле. В C # это ограничено параметрами.

И хотя существует unsafe способ (указатель на int, int*), сложности работы с GC в этом сценарии делают его нецелесообразным и неэффективным.

Итак, ваш второй пример выглядит хорошо.

3 голосов
/ 31 мая 2010

Вы не можете сохранить ссылку на переменную именно по той причине, что кто-то может сделать то, что вы делаете: взять ссылку на локальную переменную, а затем использовать эту ссылку после восстановления хранилища локальной переменной.

Ваш подход преобразования переменной в поле класса - это хорошо. Альтернативный способ сделать то же самое - создать делегаты getter и setter для переменной. Если делегаты закрыты по внешней локальной переменной, эта внешняя локальная область будет поднята в поле, так что ее время жизни больше, чем у делегатов.

1 голос
/ 30 мая 2010

Невозможно сохранить ссылку как поле.

Вам нужно держать int в классе.

...