2009-10-28 12 views
9

En .NET 4 beta 2, existe el nuevo espacio de nombres de Numerics con struct BigInteger. El documentation indica que es un tipo inmutable, como era de esperar.¿BigInnteger es inmutable o no?

Pero estoy un poco confundido por el operador de incremento posterior (++). Esto definitivamente parece mutar el valor. El siguiente bucle while funciona:

static BigInteger Factorial(BigInteger n) 
{ 
    BigInteger result = BigInteger.One; 
    BigInteger b = BigInteger.One; 

    while (b <= n) 
    { 
     result = result * b; 
     b++; // immutable ? 
    } 
    return result; 
} 

Esto es lo MSDN tiene que decir sobre el operador de incremento:

Dado que los objetos BigInteger son inmutable, el operador de incremento crea un nuevo objeto BigInteger cuya el valor es uno más que el objeto BigInteger representado por valor. Por lo tanto, las llamadas repetidas al Incremento pueden ser costosas.

Todo esto está muy bien, lo habría entendido si tuviera que utilizar b = b++ pero al parecer ++ por sí sola es suficiente para cambiar un valor.

¿Alguna idea?

Editar:
Como Lasse señala, hay un step-by-step specification de cómo funciona el post-incremento. Pero esto todavía parece estar en desacuerdo con la inmutabilidad. Por ejemplo, no me puedo imaginar que el uso de este operador sea seguro para subprocesos.

Respuesta

13

Los operadores ++ y -- se implementan en términos de las normales + y - operadores, por lo que en la realidad:

b++; 

es equivalente a:

var temp = b; 
b = b + 1; 
<use temp for the expression where b++ was located> 

Ahora bien, como se ha comentado, esto podría parece que rompe la inmutabilidad, pero no es así.

su lugar, debe mirar a este código como hacer esto:

var temp = b; 
b = BigInteger.op_Add(b, 1); // constructs a new BigInteger value 
<use temp ...> 

Esto dejará dos objetos en la memoria, el valor original BigInteger, y el nuevo, ahora referenciado por b. Se puede comprobar fácilmente que esto es lo que sucede con el siguiente código:

var x = b; 
b++; 
// now inspect the contents of x and b, and you'll notice that they differ 

lo tanto, el objeto original no cambió, por lo tanto, no se rompe la inmutabilidad, y para responder a la nueva parte de la pregunta, esto debería ser el hilo -seguro.

Esto es lo mismo que sucede con las cadenas:

String s1 = s2; 
s2 += "More"; 
// now inspect s1 and s2, they will differ 
+0

Suena razonable, pero aún parece romper la inmutabilidad. Voy a editar la pregunta un poco. –

+1

No, no interrumpe la inmutabilidad, déjame actualizar mi respuesta. –

+2

En 's + = s2' hay una asignación visible. Se ajusta si acepta que 'b ++' también es una asignación, es decir, 'b = b + 1'. Pero '++' todavía se siente/parece que está mutando. –

3

Desde BigInteger es inmutable, b ++ habrá apenas equivalente a:

BigInteger temp=b; 
b=temp+1; 

Después de esta operación, la temperatura se recicla por la GC y la memoria es liberada.

+1

OK, excepto la parte GC. Es una estructura (con una matriz interna). –

+0

Sí, y la única diferencia es que struct se almacena en la pila mientras esta clase se almacena en el montón. –

+0

Ted, ¿dónde crees que se almacena un campo BigInteger en un objeto? –