Frage

In .NET 4 Beta 2 gibt es den neuen Numerik-Namensraum mit struct BigInteger. Die Dokumentation besagt, dass es ist eine unveränderliche Art, wie ich es erwartet hätte.

Aber ich bin ein wenig verwirrt durch den Post-Inkrement-Operator (++). Dies scheint auf jeden Fall den Wert zu mutieren. Die folgende while-Schleife funktioniert:

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

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

Dies ist, was MSDN über den Inkrementoperator zu sagen hat:

  

Da BigInteger-Objekte sind   unveränderlich, der Inkrementoperator   erstellt ein neues BigInteger-Objekt, das   Wert ist eine mehr als die BigInteger   Objekt nach Wert dargestellt.   Daher wiederholte Anrufe zu erhöhen   kann teuer sein.

Alles gut und schön, würde ich es verstanden, wenn ich b = b++ verwenden musste aber anscheinend ++ selbst genug ist, um einen Wert zu ändern.

Alle Gedanken?

War es hilfreich?

Lösung

Die Betreiber ++ und -- sind in Bezug auf den normalen + und - Betreiber umgesetzt, so in der Realität:

b++;

entspricht:

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

Jetzt, da kommentierte dies könnte scheinen, wie es Unveränderlichkeit bricht, aber es funktioniert nicht.

Sie sollten stattdessen an diesem Code aussehen wie dies zu tun:

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

Dies wird zwei Objekte im Speicher verlassen, der ursprüngliche BigInteger-Wert und die neuen, nun b verwiesen. Sie können ganz einfach überprüfen, ob dies ist, was mit dem folgenden Code geschieht:

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

So das ursprüngliche Objekt nicht ändern, damit es nicht Unveränderlichkeit nicht bricht, und den neuen Teil der Frage zu beantworten, sollte diese Thread-sicher sein.

Dies ist die gleiche Sache, die Strings geschieht:

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

Andere Tipps

Da BigInteger ist unveränderlich, b ++ nur gleichwertig sein wird:

BigInteger temp=b;
b=temp+1;

Nach dieser Operation Temperatur durch die GC zurückgeführt wird und der Speicher freigegeben wird.

BigInteger b = BigInteger.One;

b++;  // immutable ?

In Ihrem Beispiel b ist eine Variable, die in der aktuellen Methode des Stapelrahmen nur ein Schlitz des Gedächtnisses ist. Es wird auf eins initialisiert, und b ++ nimmt b, erstellt ein neues BigInteger (mit dem erhöhten Wert) und gibt ihn zurück. Variable b hat nun den Zustand der zurückgegebenen neuen BigInteger.

Um ehrlich zu sein Unveränderlichkeit als ein Konzept, viel klarer ist, wenn sie mit Referenztypen zu tun, weil es ein Objekt auf dem Heap, deren inneren Zustand ändert mich nie, so, wenn eine Operation / Methode ein neues Objekt mit unterschiedlichem Zustand zurückkehrt, ist es ziemlich offensichtlich (zB kann man mit object.ReferenceEquals eine Objektverweis Gleichheitsprüfung tun (Objekt, Objekt).

Für Werttypen gibt es kein Objekt auf dem Heap, es ist nur der Schlitz in Speicher, der die Bits enthält, die den Wert sind.

Ok, aber was ist mit dem unären Negation Operator, der auf BigInteger definiert ist:

public static BigInteger operator -(BigInteger value)
{
    value._sign = -value._sign;
    return value;
}

es erscheint die Unveränderlichkeit Muster zu durchbrechen und direkt das BigInteger Objekt mutieren. So

b = -b;

tatsächlich ändert eine bestehende BigInteger anstelle, ohne ein neues Objekt zurück.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top