Ich habe sie gesehen , sowohl in zahlreichen Stücken von C # -Code verwendet wird, und ich würde gerne wissen , wann zu verwenden , i++oder ++i( ieine Zahl Variable wie int, float, doubleusw.). Wer weiß das?
Ich habe sie gesehen , sowohl in zahlreichen Stücken von C # -Code verwendet wird, und ich würde gerne wissen , wann zu verwenden , i++oder ++i( ieine Zahl Variable wie int, float, doubleusw.). Wer weiß das?
Antworten:
Seltsamerweise sehen die beiden anderen Antworten nicht so aus, und es lohnt sich auf jeden Fall zu sagen:
i++bedeutet "Sag mir den Wert von i, dann inkrementiere"
++ibedeutet "inkrementieren i, dann sag mir den Wert"
Sie sind Pre-Inkrement- und Post-Inkrement-Operatoren. In beiden Fällen wird die Variable inkrementiert . Wenn Sie jedoch den Wert beider Ausdrücke in genau denselben Fällen verwenden, unterscheidet sich das Ergebnis.
Die typische Antwort auf diese Frage, die leider bereits hier veröffentlicht wurde, lautet, dass einer das Inkrement "vor" verbleibenden Operationen und der andere das Inkrement "nach" verbleibenden Operationen ausführt. Obwohl dies die Idee intuitiv vermittelt, ist diese Aussage auf den ersten Blick völlig falsch . Die zeitliche Abfolge von Ereignissen ist in C # sehr genau definiert, und es ist ausdrücklich nicht der Fall, dass die Präfix- (++ var) und Postfix- (var ++) Versionen von ++ die Dinge in einer anderen Reihenfolge als andere Operationen ausführen.
Es ist nicht überraschend, dass Sie viele falsche Antworten auf diese Frage sehen. Sehr viele "Teach yourself C #" - Bücher verstehen es auch falsch. Auch die Art und Weise, wie C # es macht, unterscheidet sich von der Art und Weise, wie C es macht. Viele Leute argumentieren, dass C # und C dieselbe Sprache sind; Sie sind nicht. Das Design der Inkrement- und Dekrementoperatoren in C # vermeidet meiner Meinung nach die Designfehler dieser Operatoren in C.
Es gibt zwei Fragen, die beantwortet werden müssen, um festzustellen, wie genau Präfix und Postfix ++ in C # funktionieren. Die erste Frage ist was ist das Ergebnis? und die zweite Frage ist, wann die Nebenwirkung des Inkrements auftritt?
Es ist nicht offensichtlich, wie die Antwort auf eine der beiden Fragen lautet, aber es ist tatsächlich recht einfach, sobald Sie sie sehen. Lassen Sie mich genau erläutern, was x ++ und ++ x für eine Variable x tun.
Für das Präfixformular (++ x):
Für das Postfix-Formular (x ++):
Einige Dinge zu beachten:
Erstens ist die zeitliche Reihenfolge der Ereignisse in beiden Fällen genau gleich . Auch hier ist es absolut nicht der Fall, dass sich die zeitliche Reihenfolge der Ereignisse zwischen Präfix und Postfix ändert. Es ist völlig falsch zu sagen, dass die Bewertung vor anderen Bewertungen oder nach anderen Bewertungen erfolgt. Die Auswertungen erfolgen in beiden Fällen in genau derselben Reihenfolge, wie Sie anhand der Schritte 1 bis 4 sehen können, die identisch sind. Der einzige Unterschied ist der letzte Schritt - ob das Ergebnis der Wert des temporären oder des neuen inkrementierten Werts ist.
Sie können dies einfach mit einer einfachen C # -Konsolen-App demonstrieren:
public class Application
{
public static int currentValue = 0;
public static void Main()
{
Console.WriteLine("Test 1: ++x");
(++currentValue).TestMethod();
Console.WriteLine("\nTest 2: x++");
(currentValue++).TestMethod();
Console.WriteLine("\nTest 3: ++x");
(++currentValue).TestMethod();
Console.ReadKey();
}
}
public static class ExtensionMethods
{
public static void TestMethod(this int passedInValue)
{
Console.WriteLine("Current:{0} Passed-in:{1}",
Application.currentValue,
passedInValue);
}
}
Hier sind die Ergebnisse...
Test 1: ++x
Current:1 Passed-in:1
Test 2: x++
Current:2 Passed-in:1
Test 3: ++x
Current:3 Passed-in:3
Im ersten Test können Sie sehen, dass beide currentValueund was an die übergeben wurdeTestMethod() Erweiterung übergeben wurde, erwartungsgemäß denselben Wert aufweisen.
Doch im zweiten Fall werden versuchen , die Menschen zu sagen , dass der Zuwachs von currentValuegeschieht nach dem Aufruf TestMethod(), aber wie Sie aus den Ergebnissen sehen können, kommt es vor dem Aufruf , wie durch die angezeigte ‚Laufend: 2‘ Ergebnis.
In diesem Fall wird zunächst der Wert von currentValuein einem temporären gespeichert. Als nächstes wird eine inkrementierte Version dieses Werts wieder gespeichert currentValue, ohne jedoch die temporäre Version zu berühren, in der der ursprüngliche Wert noch gespeichert ist . Schließlich wird dieses temporäre an übergeben TestMethod(). Wenn das Inkrement nach dem Aufruf von erfolgt TestMethod(), wird derselbe, nicht inkrementierte Wert zweimal ausgeschrieben, dies ist jedoch nicht der Fall.
Es ist wichtig , dass der Wert von sowohl die zurück beachten
currentValue++und++currentValuewerden Operationen auf der Grundlage der temporären und nicht der in der Variablen gespeicherten Istwert zu der Zeit entweder Operation beendet.In der obigen Reihenfolge der Operationen kopieren die ersten beiden Schritte den dann aktuellen Wert der Variablen in die temporäre. Damit wird der Rückgabewert berechnet. Bei der Präfixversion wird der temporäre Wert erhöht, bei der Suffix-Version wird dieser Wert direkt / nicht erhöht. Die Variable selbst wird nach dem ersten Speichern im Temporär nicht erneut gelesen.
Einfacher ausgedrückt gibt die Postfix-Version den Wert zurück, der aus der Variablen gelesen wurde (dh den Wert der temporären Variable), während die Präfix-Version den Wert zurückgibt, der in die Variable zurückgeschrieben wurde (dh den inkrementierten Wert der temporären Variable). Weder geben Sie den Wert der Variablen zurück.
Dies ist wichtig zu verstehen, da die Variable selbst möglicherweise flüchtig ist und sich in einem anderen Thread geändert hat. Dies bedeutet, dass der Rückgabewert dieser Operationen vom aktuellen Wert in der Variablen abweichen kann.
Es ist überraschend häufig, dass Menschen in Bezug auf Vorrang, Assoziativität und die Reihenfolge, in der Nebenwirkungen ausgeführt werden, sehr verwirrt sind. Ich vermute vor allem, dass es in C so verwirrend ist. C # wurde sorgfältig entworfen, um in all diesen Punkten weniger verwirrend zu sein. Für eine zusätzliche Analyse dieser Probleme, einschließlich meiner weiteren Demonstration der Falschheit der Idee, dass Präfix- und Postfix-Operationen "Dinge in der Zeit verschieben", siehe:
https://ericlippert.com/2009/08/10/precedence-vs-order-redux/
was zu dieser SO-Frage führte:
int [] arr = {0}; int value = arr [arr [0] ++]; Wert = 1?
Vielleicht interessieren Sie sich auch für meine vorherigen Artikel zu diesem Thema:
https://ericlippert.com/2008/05/23/precedence-vs-associativity-vs-order/
und
https://ericlippert.com/2007/08/14/c-and-the-pit-of-despair/
und ein interessanter Fall, in dem C es schwierig macht, über die Richtigkeit nachzudenken:
https://docs.microsoft.com/archive/blogs/ericlippert/bad-recursion-revisited
Außerdem stoßen wir auf ähnliche subtile Probleme, wenn wir andere Vorgänge mit Nebenwirkungen in Betracht ziehen, z. B. verkettete einfache Zuweisungen:
https://docs.microsoft.com/archive/blogs/ericlippert/chaining-simple-assignments-is-not-so-simple
Und hier ist ein interessanter Beitrag darüber, warum die Inkrementoperatoren zu Werten in C # und nicht zu Variablen führen :
Warum kann ich ++ i ++ nicht in C-ähnlichen Sprachen ausführen?
i++oder ++iin Code verwendet, die Dinge auf im Hintergrund gehen nur das; im Hintergrund . Ich schreibe C #, um zu Abstraktionsebenen zu gelangen, die über dem liegen, was auf dieser Ebene vor sich geht. Wenn dies also für Ihren C # -Code wirklich wichtig ist, sind Sie möglicherweise bereits in der falschen Sprache.
i++;) for (int i = 0; i < x; i++)... Und ich bin sehr sehr glücklich darüber! (und ich benutze niemals den Präfix-Operator). Wenn ich etwas schreiben muss, für dessen Entschlüsselung ein erfahrener Programmierer 2 Minuten benötigt ... Nun ... Es ist besser, eine weitere Codezeile zu schreiben oder eine temporäre Variable einzuführen :-) Ich denke, dass Ihr "Artikel" (ich habe gewonnen) nenne es nicht "Antwort") bestätigt meine Wahl :-)
Wenn Sie haben:
int i = 10;
int x = ++i;
dann xwird es sein 11.
Aber wenn Sie haben:
int i = 10;
int x = i++;
dann xwird es sein 10.
Beachten Sie, wie Eric betont, dass das Inkrement in beiden Fällen zur gleichen Zeit erfolgt, aber es ist der Wert, der als Ergebnis angegeben wird, der sich unterscheidet (danke Eric!).
Im Allgemeinen verwende ich gerne, es ++isei denn, es gibt einen guten Grund, dies nicht zu tun. Wenn ich zum Beispiel eine Schleife schreibe, verwende ich gerne:
for (int i = 0; i < 10; ++i) {
}
Oder wenn ich nur eine Variable inkrementieren muss, verwende ich gerne:
++x;
Normalerweise hat die eine oder andere Art keine große Bedeutung und hängt vom Codierungsstil ab. Wenn Sie jedoch die Operatoren in anderen Zuordnungen verwenden (wie in meinen ursprünglichen Beispielen), ist es wichtig, sich möglicher Nebenwirkungen bewusst zu sein.
ifür den Variablennamen und nicht varals C # -Schlüsselwort verwendet wird.
int i = 0;
Console.WriteLine(i++); // Prints 0. Then value of "i" becomes 1.
Console.WriteLine(--i); // Value of "i" becomes 0. Then prints 0.
Beantwortet das deine Frage ?
Der Operator arbeitet so, dass er gleichzeitig inkrementiert wird. Wenn er sich jedoch vor einer Variablen befindet, wird der Ausdruck mit der inkrementierten / dekrementierten Variablen ausgewertet:
int x = 0; //x is 0
int y = ++x; //x is 1 and y is 1
Wenn es nach der Variablen liegt, wird die aktuelle Anweisung mit der ursprünglichen Variablen ausgeführt, als ob sie noch nicht inkrementiert / dekrementiert worden wäre:
int x = 0; //x is 0
int y = x++; //'y = x' is evaluated with x=0, but x is still incremented. So, x is 1, but y is 0
Ich stimme dcp bei der Verwendung von Pre-Inkrement / Decrement (++ x) zu, sofern dies nicht erforderlich ist. Wirklich das einzige Mal, dass ich das Post-Inkrementieren / Dekrementieren verwende, ist while-Schleifen oder Schleifen dieser Art. Diese Schleifen sind die gleichen:
while (x < 5) //evaluates conditional statement
{
//some code
++x; //increments x
}
oder
while (x++ < 5) //evaluates conditional statement with x value before increment, and x is incremented
{
//some code
}
Sie können dies auch beim Indizieren von Arrays und dergleichen tun:
int i = 0;
int[] MyArray = new int[2];
MyArray[i++] = 1234; //sets array at index 0 to '1234' and i is incremented
MyArray[i] = 5678; //sets array at index 1 to '5678'
int temp = MyArray[--i]; //temp is 1234 (becasue of pre-decrement);
Usw.
Nur für den Datensatz ist in C ++ der Präfixoperator effizienter, wenn Sie entweder (dh) die Reihenfolge der Operationen nicht interessieren (Sie möchten sie nur inkrementieren oder dekrementieren und später verwenden), da dies nicht der Fall ist müssen eine temporäre Kopie des Objekts erstellen. Leider verwenden die meisten Leute Posfix (var ++) anstelle von Präfix (++ var), nur weil wir das anfangs gelernt haben. (Ich wurde in einem Interview danach gefragt). Ich bin mir nicht sicher, ob dies in C # zutrifft, aber ich gehe davon aus, dass dies der Fall ist.