2009-10-28 10 views
9

In .NET 4 beta 2, c'è il nuovo spazio dei nomi Numerics con struct BigInteger. Lo documentation afferma che è un tipo immutabile, come mi sarei aspettato.BigInteger è immutabile o no?

Ma sono un po 'confuso dall'operatore post-incremento (++). Questo sembra decisamente mutare il valore. Il seguente ciclo while funziona:

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

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

Questo è ciò che MSDN ha da dire circa l'operatore di incremento:

Poiché gli oggetti BigInteger sono immutabili, l'operatore di incremento crea un nuovo oggetto BigInteger cui valore è uno in più rispetto all'oggetto BigInteger rappresentato dal valore. Pertanto, le chiamate ripetute a Incremento possono essere costose.

Tutto molto bene, avrei capito se ho dovuto usare b = b++ ma a quanto pare ++ di per sé è sufficiente per cambiare un valore.

Qualche idea?

Modifica:
Come sottolinea Lasse, c'è un step-by-step specification per come funziona il post-incremento. Ma questo sembra ancora in disaccordo con l'immutabilità. Ad esempio, non posso immaginare che l'utilizzo di questo operatore sia sicuro per i thread.

risposta

13

Gli operatori ++ e -- sono implementate in termini di normali + e - operatori, quindi in realtà:

b++; 

è equivalente a:

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

Ora, come ha commentato, questo potrebbe sembra che rompa l'immutabilità, ma non è così.

Si dovrebbe invece guardare a questo codice come fare questo:

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

Questo lascerà due oggetti in memoria, il valore originale BigInteger, e quello nuovo, ora fa riferimento b. Si può facilmente verificare che questo è ciò che accade con il seguente codice:

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

Così l'oggetto originale non è cambiata, quindi non si rompe immutabilità, e per rispondere alla nuova parte della domanda, questo dovrebbe essere discussione -sicuro.

Questa è la stessa cosa che accade alle stringhe:

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

Suoni ragionevoli, ma sembra ancora rompere l'immutabilità. Modificherò la domanda un po '. –

+1

No, non infrange l'immutabilità, lascia che aggiorni la mia risposta. –

+2

In 's + = s2' c'è un incarico visibile. Si adatta se si accetta che 'b ++' sia anche un compito, ovvero 'b = b + 1'. Ma '++' sembra ancora/sembra che stia mutando. –

3

Da BigInteger è immutabile, b ++ sarà solo equivalente a:

BigInteger temp=b; 
b=temp+1; 

Dopo questa operazione, la temperatura viene riciclato dal GC e il ricordo è liberato.

+1

OK, tranne per la parte GC. È una struttura (con un array interno). –

+0

Sì, e l'unica differenza è che struct è memorizzata nello stack mentre questa classe è archiviata nell'heap. –

+0

Ted, dove pensi che sia archiviato un campo BigInteger in un oggetto? –