Aku pernah melihat mereka berdua sedang digunakan dalam berbagai potongan kode C #, dan saya ingin tahu kapan harus menggunakan i++atau ++i( imenjadi variabel nomor seperti int, float, double, dll). Adakah yang tahu ini?
Aku pernah melihat mereka berdua sedang digunakan dalam berbagai potongan kode C #, dan saya ingin tahu kapan harus menggunakan i++atau ++i( imenjadi variabel nomor seperti int, float, double, dll). Adakah yang tahu ini?
Jawaban:
Anehnya, sepertinya dua jawaban lainnya tidak menjelaskannya, dan itu layak untuk dikatakan:
i++berarti 'beri tahu saya nilai i, lalu kenaikan'
++iberarti 'kenaikan i, lalu beri tahu saya nilai'
Mereka adalah operator pra-kenaikan, pasca kenaikan. Dalam kedua kasus, variabel bertambah , tetapi jika Anda mengambil nilai dari kedua ekspresi dalam kasus yang persis sama, hasilnya akan berbeda.
Jawaban khas untuk pertanyaan ini, sayangnya sudah diposting di sini, adalah bahwa seseorang melakukan kenaikan "sebelum" operasi yang tersisa dan yang lainnya melakukan kenaikan "setelah" operasi yang tersisa. Meskipun itu secara intuisi menyampaikan gagasan, pernyataan itu benar-benar salah . The urutan kejadian dalam waktu sangat baik didefinisikan dalam C #, dan itu adalah tegas tidak terjadi bahwa awalan (var ++) dan postfix (var ++) versi ++ melakukan hal-hal dalam urutan yang berbeda sehubungan dengan operasi lainnya.
Tidak mengherankan bahwa Anda akan melihat banyak jawaban yang salah untuk pertanyaan ini. Banyak sekali buku "ajarkan diri Anda C #" yang salah. Juga, cara C # melakukannya berbeda dari cara C melakukannya. Banyak orang beralasan seolah-olah C # dan C adalah bahasa yang sama; mereka tidak. Desain operator kenaikan dan penurunan dalam C # menurut pendapat saya menghindari cacat desain operator ini di C.
Ada dua pertanyaan yang harus dijawab untuk menentukan apa sebenarnya operasi awalan dan postfix ++ di C #. Pertanyaan pertama adalah apa hasilnya? dan pertanyaan kedua adalah kapan efek samping kenaikan itu terjadi?
Tidak jelas apa jawaban dari kedua pertanyaan itu, tetapi sebenarnya cukup sederhana begitu Anda melihatnya. Biarkan saya menguraikan untuk Anda apa yang dilakukan x ++ dan ++ x untuk variabel x.
Untuk formulir awalan (++ x):
Untuk bentuk postfix (x ++):
Beberapa hal yang perlu diperhatikan:
Pertama, urutan peristiwa dalam waktu persis sama dalam kedua kasus . Sekali lagi, itu sama sekali tidak terjadi bahwa urutan peristiwa dalam waktu berubah antara awalan dan postfix. Adalah sepenuhnya salah untuk mengatakan bahwa evaluasi terjadi sebelum evaluasi lain atau setelah evaluasi lainnya. Evaluasi terjadi dalam urutan yang persis sama dalam kedua kasus seperti yang Anda lihat dengan langkah 1 hingga 4 identik. Satu- satunya perbedaan adalah langkah terakhir - apakah hasilnya adalah nilai sementara, atau baru, nilai tambah.
Anda dapat dengan mudah menunjukkan ini dengan aplikasi konsol C # sederhana:
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);
}
}
Inilah hasilnya ...
Test 1: ++x
Current:1 Passed-in:1
Test 2: x++
Current:2 Passed-in:1
Test 3: ++x
Current:3 Passed-in:3
Di tes pertama, Anda dapat melihat bahwa keduanya currentValuedan apa yang diteruskan keTestMethod() ekstensi menunjukkan nilai yang sama, seperti yang diharapkan.
Namun, dalam kasus kedua, orang akan mencoba memberi tahu Anda bahwa kenaikan currentValueterjadi setelah panggilan TestMethod(), tetapi seperti yang Anda lihat dari hasilnya, itu terjadi sebelum panggilan seperti ditunjukkan oleh hasil 'Saat ini: 2'.
Dalam hal ini, pertama nilai currentValuedisimpan sementara. Selanjutnya, versi yang meningkat dari nilai tersebut disimpan kembali currentValuetetapi tanpa menyentuh sementara yang masih menyimpan nilai aslinya. Akhirnya sementara itu diteruskan ke TestMethod(). Jika kenaikan terjadi setelah panggilan ke TestMethod()maka akan menuliskan nilai yang sama, yang tidak bertambah dua kali, tetapi tidak.
Penting untuk dicatat bahwa nilai yang dikembalikan dari kedua
currentValue++dan++currentValueoperasi didasarkan pada nilai sementara dan bukan yang sebenarnya disimpan dalam variabel pada saat salah satu operasi keluar.Ingat dalam urutan operasi di atas, dua langkah pertama menyalin nilai variabel saat itu ke variabel sementara. Itulah yang digunakan untuk menghitung nilai pengembalian; dalam kasus versi awalan, itu adalah nilai sementara yang meningkat sementara dalam kasus versi akhiran, itu nilai yang langsung / tidak bertambah. Variabel itu sendiri tidak dibaca lagi setelah penyimpanan awal menjadi sementara.
Sederhananya, versi postfix mengembalikan nilai yang telah dibaca dari variabel (yaitu nilai temporer) sedangkan versi awalan mengembalikan nilai yang ditulis kembali ke variabel (yaitu nilai temporer yang meningkat). Tidak mengembalikan nilai variabel.
Ini penting untuk dipahami karena variabel itu sendiri dapat berubah-ubah dan telah berubah pada utas lainnya yang berarti nilai pengembalian operasi tersebut dapat berbeda dari nilai saat ini yang disimpan dalam variabel.
Sangat mengejutkan bagi orang untuk menjadi sangat bingung tentang presedensi, asosiatif, dan urutan di mana efek samping dieksekusi, saya menduga sebagian besar karena itu sangat membingungkan dalam C. C # telah dirancang dengan hati-hati untuk menjadi kurang membingungkan dalam semua hal ini. Untuk beberapa analisis tambahan tentang masalah-masalah ini, termasuk saya lebih lanjut menunjukkan kepalsuan gagasan bahwa operasi awalan dan postfix "memindahkan barang dalam waktu" lihat:
https://ericlippert.com/2009/08/10/precedence-vs-order-redux/
yang mengarah pada pertanyaan SO ini:
int [] arr = {0}; int value = arr [arr [0] ++]; Nilai = 1?
Anda mungkin juga tertarik dengan artikel saya sebelumnya tentang masalah ini:
https://ericlippert.com/2008/05/23/precedence-vs-associativity-vs-order/
dan
https://ericlippert.com/2007/08/14/c-and-the-pit-of-despair/
dan kasus yang menarik di mana C mempersulit pemikiran tentang kebenaran:
https://docs.microsoft.com/archive/blogs/ericlippert/bad-recursion-revisited
Juga, kami mengalami masalah serupa yang serupa ketika mempertimbangkan operasi lain yang memiliki efek samping, seperti tugas sederhana dirantai:
https://docs.microsoft.com/archive/blogs/ericlippert/chaining-simple-assignments-is-not-so-simple
Dan inilah pos yang menarik tentang mengapa operator kenaikan menghasilkan nilai dalam C # daripada dalam variabel :
Mengapa saya tidak bisa melakukan ++ i ++ dalam bahasa C-like?
i++atau ++idigunakan dalam kode, hal-hal yang terjadi di latar belakang hanya itu; di latar belakang . Saya menulis C # untuk naik ke level abstraksi di atas apa yang terjadi pada level ini, jadi jika ini benar-benar penting untuk kode C # Anda, Anda mungkin sudah menggunakan bahasa yang salah.
i++;) di for (int i = 0; i < x; i++)... Dan saya sangat sangat senang dengan ini! (dan saya tidak pernah menggunakan operator awalan). Jika saya harus menulis sesuatu yang akan membutuhkan programmer senior 2 menit untuk menguraikan ... Yah ... Lebih baik menulis satu baris kode lagi atau memperkenalkan variabel sementara :-) Saya rasa "artikel" Anda (saya menang sebut saja "jawab") membuktikan pilihan saya :-)
Jika Anda memiliki:
int i = 10;
int x = ++i;
maka xakan 11.
Tetapi jika Anda memiliki:
int i = 10;
int x = i++;
maka xakan 10.
Perhatikan sebagaimana Eric tunjukkan, kenaikan terjadi pada waktu yang sama dalam kedua kasus, tetapi nilai itulah yang diberikan sebagai hasil yang berbeda (terima kasih Eric!).
Secara umum, saya suka menggunakan ++ikecuali ada alasan bagus untuk tidak melakukannya. Misalnya, saat menulis loop, saya suka menggunakan:
for (int i = 0; i < 10; ++i) {
}
Atau, jika saya hanya perlu menambahkan variabel, saya suka menggunakan:
++x;
Biasanya, satu cara atau yang lain tidak memiliki banyak arti dan turun ke gaya pengkodean, tetapi jika Anda menggunakan operator di dalam tugas lain (seperti dalam contoh asli saya), penting untuk mengetahui potensi efek samping.
iuntuk nama variabel daripada varkarena kata kunci C #.
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.
Apakah ini menjawab pertanyaan Anda?
Cara kerja operator adalah bahwa ia bertambah pada saat yang sama, tetapi jika sebelum variabel, ekspresi akan dievaluasi dengan variabel yang bertambah / dikurangi:
int x = 0; //x is 0
int y = ++x; //x is 1 and y is 1
Jika setelah variabel, pernyataan saat ini akan dieksekusi dengan variabel asli, seolah-olah belum ditambahkan / dikurangi:
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
Saya setuju dengan dcp dalam menggunakan pre-increment / decrement (++ x) kecuali perlu. Sungguh satu-satunya waktu saya menggunakan post-increment / decrement adalah saat loop atau loop semacam itu. Loop-loop ini sama:
while (x < 5) //evaluates conditional statement
{
//some code
++x; //increments x
}
atau
while (x++ < 5) //evaluates conditional statement with x value before increment, and x is incremented
{
//some code
}
Anda juga dapat melakukan ini saat mengindeks array dan semacamnya:
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);
Dll, dll ...
Sebagai catatan saja, di C ++, jika Anda dapat menggunakan salah satu (yaitu) Anda tidak peduli tentang urutan operasi (Anda hanya ingin menambah atau mengurangi dan menggunakannya nanti) operator awalan lebih efisien karena tidak harus membuat salinan sementara objek. Sayangnya, kebanyakan orang menggunakan posfix (var ++) alih-alih prefix (++ var), hanya karena itulah yang kami pelajari pada awalnya. (Saya ditanya tentang hal ini dalam sebuah wawancara). Tidak yakin apakah ini benar dalam C #, tapi saya anggap itu benar.