2010-05-30 12 views
5

Aquí es una versión muy simplificada de lo que estoy tratando de hacerguardar una referencia a 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); 
    } 
} 

En mi código real que tengo un int que se incrementa en muchos hilos Sin embargo, donde los hilos de una llama no será fácil pasarle el parámetro que lo señala en el int (en el código real esto está sucediendo dentro de un IEnumerator). Entonces, un requisito es que la referencia debe hacerse en el constructor. Además, no todos los hilos apuntan a la misma base única int, por lo que tampoco puedo usar una int global estática. Sé que puedo encasillar el int dentro de una clase y pasar la clase, pero quería saber si esa es la forma correcta de hacer algo como esto.

Lo que creo que podría ser la manera correcta:

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

¿Hay una manera mejor que esto?

Respuesta

5

Básicamente, la respuesta es Sí, necesita una clase.

No existe el concepto de 'referencia a int' que puede almacenar como un campo. En C# está limitado a los parámetros.

Y si bien hay una forma unsafe (puntero a int, int*) las complejidades de tratar con el GC en ese escenario lo hacen impráctico e ineficiente.

Por lo tanto, su segundo ejemplo se ve bien.

1

No se puede almacenar una referencia como campo.

Necesita mantener el int en una clase.

+0

¿Eso significa que mi segundo ejemplo es la manera de hacerlo? –

+0

Si necesita hacerlo, sí, o puede cambiar a código inseguro y punteros de lobby. –

+0

@Lase: pero tendrías que 'fijar' los objetivos. No es muy práctico. –

3

No se puede almacenar una referencia a una variable, precisamente por la razón de que alguien pudiera hacer lo que está haciendo: tomar una referencia a una variable local, y luego usar esa referencia después del almacenamiento de la variable local se reclama.

Su enfoque de convertir la variable en un campo de una clase está bien. Una forma alternativa de hacer lo mismo es hacer delegados getter y setter a la variable. Si los delegados se cierran sobre una variable local externa, ese local externo se izará a un campo para que su duración sea más larga que la de los delegados.

Cuestiones relacionadas