2010-05-30 33 views
5

Voici une version très simplifiée de ce que je suis en train de faireEnregistrement d'une référence à un 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); 
    } 
} 

Dans mon code réel que j'ai un int qui sera incrémenté de nombreux fils mais où les fils d'un appelé il ne sera pas facile de lui passer le paramètre qui le pointe à l'int (dans le vrai code cela se passe à l'intérieur d'un IEnumerator). Donc, une exigence est la référence doit être faite dans le constructeur. De même, tous les threads ne pointeront pas sur la même base int, donc je ne peux pas non plus utiliser un static statique global. Je sais que je peux juste boxer l'int à l'intérieur d'une classe et passer le cours, mais je voulais savoir si c'est la bonne façon de faire quelque chose comme ça?

Ce que je pense pourrait être la bonne façon:

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

Y at-il une meilleure façon que cela?

Répondre

5

Fondamentalement, la réponse est Oui, vous avez besoin d'une classe.

Il n'existe aucun concept de 'référence à int' que vous pouvez stocker en tant que champ. En C#, il est limité aux paramètres.

Et bien qu'il existe une manière unsafe (pointeur sur int, int*), les complexités liées à l'utilisation du GC dans ce scénario le rendent peu pratique et inefficace.

Votre deuxième exemple semble donc OK.

1

Il n'est pas possible de stocker une référence en tant que champ.

Vous devez maintenir int dans une classe.

+0

Est-ce que cela signifie que mon deuxième exemple est la façon de faire les «meilleures pratiques»? –

+0

Si vous avez besoin de le faire, oui, ou vous pouvez basculer vers un code dangereux et des pointeurs de lobby autour. –

+0

@Lase: mais vous devez "épingler" les cibles. Pas très pratique. –

3

Vous ne pouvez pas stocker une référence à une variable, précisément pour la raison que quelqu'un pourrait faire ce que vous faites: prendre une référence à une variable locale, puis utiliser cette référence après que le stockage de la variable locale est récupéré.

Votre approche de faire de la variable dans un champ d'une classe est bien. Une autre façon de faire la même chose est de faire des délégués getter et setter à la variable. Si les délégués sont fermés sur une variable locale externe, cette locale externe sera hissée à un champ afin que sa durée de vie soit plus longue que celle des délégués.