2010-05-30 2 views
5

Здесь гораздо упрощенная версия того, что я пытаюсь сделатьСохранения ссылки на Int

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, поэтому я не могу использовать глобальный статический 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); 
    } 
} 

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

ответ

5

В принципе, ответ Да, вам нужен класс.

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

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

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

1

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

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

+0

Означает ли это, что мой второй пример - это способ «наилучших практик»? –

+0

Если вам нужно это сделать, да, или вы можете переключиться на небезопасный код и указатели на лобби. –

+0

@Lase: но вам придется «привязать» цели. Не очень практично. –

3

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

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

Смежные вопросы