Hem C # kodunun sayısız parçalara kullanılıyor onları gördüm ve ben ne zaman kullanılacağını bilmek istiyorum i++veya ++i( igibi bir sayı değişken olmak int, float, double, vs). Bunu bilen var mı?
Hem C # kodunun sayısız parçalara kullanılıyor onları gördüm ve ben ne zaman kullanılacağını bilmek istiyorum i++veya ++i( igibi bir sayı değişken olmak int, float, double, vs). Bunu bilen var mı?
Yanıtlar:
Garip bir şekilde, diğer iki cevap bunu açıklamıyor gibi görünüyor ve kesinlikle söylemeye değer:
i++'bana değerini söyle isonra artır'
++i'artma i, sonra bana değeri söyle ' anlamına gelir
Bunlar Artış öncesi, artım sonrası operatörleridir. Her iki durumda da değişken artırılır , ancak her iki ifadenin değerini tam olarak aynı durumlarda alacak olsaydınız sonuç farklı olacaktır.
Maalesef burada zaten gönderilmiş olan bu sorunun tipik cevabı, kalan işlemleri "önce" ve diğerini ise "kalan" işlemleri yapar. Bu, sezgisel bir şekilde fikri karşılasa da, bu ifade tamamen yanlıştır . Zaman içindeki olayların sırası C # 'da son derece iyi tanımlanmıştır ve ++ ön eki (++ var) ve postfix (var ++) sürümlerinin diğer işlemlere göre işleri farklı bir sırayla yapması kesin değildir .
Bu soruya birçok yanlış cevap görmeniz şaşırtıcı değil. Pek çok "kendinize C # öğretin" kitapları da yanlış anlıyor. Ayrıca, C # 'ın yaptığı yol, C' nin yaptığıdan farklıdır. Birçok kişi sanki C # ve C'nin aynı dil olduğunu düşünür; onlar değil. Bence C # 'daki artış ve azalma operatörlerinin tasarımı, bu operatörlerin C'deki tasarım kusurlarını önler.
Ön ek ve postfix ++ işlemlerinin tam olarak C # 'da ne olduğunu belirlemek için yanıtlanması gereken iki soru vardır. İlk soru sonuç nedir? ikinci soru, artışın yan etkisi ne zaman gerçekleşiyor?
Her iki sorunun cevabının ne olduğu belli değil, ama bir kez gördüğünüzde oldukça basit. X değişkeninin x ++ ve ++ x tam olarak ne yaptığını sizin için açıklayayım.
Önek formu (++ x) için:
Postfix formu (x ++) için:
Dikkat edilmesi gereken bazı noktalar:
İlk olarak, olayların zaman içindeki sırası her iki durumda da tamamen aynıdır . Yine, kesinlikle olduğunu değil bu durumda zaman içinde olayların sırası öneki ve postfix arasında değişir. Değerlendirmenin diğer değerlendirmelerden önce veya diğer değerlendirmelerden sonra gerçekleştiğini söylemek tamamen yanlıştır. Değerlendirmeler , her iki durumda da aynı sırayla gerçekleşir; 1'den 4'e kadar olan adımların aynı olduğunu görebilirsiniz. Sadece fark son adım - Sonuç geçici veya yeni, artırılır değerin değeri olup olmadığını.
Bunu basit bir C # konsol uygulamasıyla kolayca gösterebilirsiniz:
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);
}
}
Sonuçlar burada...
Test 1: ++x
Current:1 Passed-in:1
Test 2: x++
Current:2 Passed-in:1
Test 3: ++x
Current:3 Passed-in:3
İlk testte, hem uzantıların hem currentValuede TestMethod()uzantıya iletilenlerin beklendiği gibi aynı değeri gösterdiğini görebilirsiniz.
Bununla birlikte, ikinci durumda, insanlar size artışın çağrıdan sonracurrentValue gerçekleştiğini söylemeye çalışacaklar , ancak sonuçlardan da görebileceğiniz gibi, 'Güncel: 2' sonucuyla belirtildiği gibi, çağrıdan önce gerçekleşiyor .TestMethod()
Bu durumda, önce değeri currentValuegeçici olarak saklanır. Daha sonra, bu değerin artırılmış bir versiyonu currentValue, orijinal değeri hala saklayan geçici değere dokunmadan geri kaydedilir . Sonunda geçici geçilir TestMethod(). Artış çağrısından sonra artış TestMethod()olsaydı, aynı, artmamış değeri iki kez yazacaktır, ancak yazmaz.
Bu dikkat etmek önemlidir her iki dönen değer
currentValue++ve++currentValueişlemleri geçici ve dayanmaktadır zaman değil, ya operasyon çıkışlarında değişkeninde saklanan gerçek değer.Yukarıdaki işlemler sırasında hatırlayın, ilk iki adım değişkenin o anki değerini geçici olarak kopyalar. Dönüş değerini hesaplamak için kullanılan budur; önek sürümü söz konusu olduğunda, bu geçici değer arttıkça, sonek sürümü söz konusu olduğunda bu değer doğrudan / artırılmazdır. Değişkenin kendisi, geçici olarak ilk depolamadan sonra tekrar okunmaz.
Daha basit bir ifadeyle, postfix sürümü değişkenden okunan değeri (yani geçici değerin değerini) döndürürken, önek sürümü değişkene geri yazılan değeri (yani geçici değerin artan değerini) döndürür. İkisi de değişkenin değerini döndürmez.
Bunu anlamak önemlidir, çünkü değişkenin kendisi değişken olabilir ve başka bir iş parçacığında değişebilir, bu da bu işlemlerin dönüş değerinin değişkente depolanan geçerli değerden farklı olabileceği anlamına gelir.
İnsanların öncelik, ilişkilendirilebilirlik ve yan etkilerin uygulanma sırası hakkında çok kafa karıştırması şaşırtıcıdır, çoğunlukla C'de çok kafa karıştırıcı olduğu için şüpheleniyorum. C #, tüm bu konularda daha az kafa karıştırıcı olacak şekilde dikkatle tasarlanmıştır. Bu sorunların bazı ek analizleri için, ön ek ve son düzeltme işlemlerinin "zaman içinde işleri hareket ettirme" fikrinin sahtelik olduğunu daha fazla göstermem de dahil olmak üzere:
https://ericlippert.com/2009/08/10/precedence-vs-order-redux/
Bu SO sorusuna yol açtı:
int [] arr = {0}; int değeri = arr [arr [0] ++]; Değer = 1?
Ayrıca konuyla ilgili önceki makalelerimle de ilgilenebilirsiniz:
https://ericlippert.com/2008/05/23/precedence-vs-associativity-vs-order/
ve
https://ericlippert.com/2007/08/14/c-and-the-pit-of-despair/
ve C'nin doğruluk hakkında akıl yürütmeyi zorlaştırdığı ilginç bir durum:
https://docs.microsoft.com/archive/blogs/ericlippert/bad-recursion-revisited
Ayrıca, zincirleme basit görevler gibi yan etkileri olan diğer işlemleri düşünürken benzer ince sorunlarla karşılaşıyoruz:
https://docs.microsoft.com/archive/blogs/ericlippert/chaining-simple-assignments-is-not-so-simple
Ve işte artım işleçlerinin neden değişkenlerden ziyade C # değerlerine neden olduğuna dair ilginç bir yazı :
i++veya ++ikodda kullanılır, arka planda olan şeyler sadece; arka planda . Bu seviyede olup bitenlerin üzerindeki soyutlama seviyelerine tırmanmak için C # yazıyorum, bu yüzden bu C # kodunuz için gerçekten önemliyse, zaten yanlış dilde olabilirsiniz.
i++;) olduğu yıllar ve yıllar for (int i = 0; i < x; i++)... Ve ben çok çok Bundan mutlu! (ve hiçbir zaman önek operatörünü kullanmam). Ben deşifre etmek için 2 dakika üst düzey bir programcı gerektirecek bir şey yazmak zorunda ... Eh ... Bir kod satırı daha yazmak veya geçici bir değişken tanıtmak daha iyidir :-) Bence "makale" (ben kazandım "cevap"
Eğer varsa:
int i = 10;
int x = ++i;
sonra xolacak 11.
Ama eğer varsa:
int i = 10;
int x = i++;
sonra xolacak 10.
Eric'in belirttiği gibi, artış her iki durumda da aynı anda gerçekleşir, ancak sonuç olarak farklı olan değer verilir (teşekkürler Eric!).
Genellikle, ++iiyi bir neden olmadığı sürece kullanmayı seviyorum . Örneğin, bir döngü yazarken şunu kullanmayı seviyorum:
for (int i = 0; i < 10; ++i) {
}
Veya, sadece bir değişkeni artırmak gerekirse, ben kullanmak istiyorum:
++x;
Normalde, şu ya da bu şekilde çok fazla önemi yoktur ve kodlama stiline iner, ancak operatörleri diğer ödevlerde (orijinal örneklerimdeki gibi) kullanıyorsanız, potansiyel yan etkilerin farkında olmak önemlidir.
iolduğu vargibi değişken adı kullanmak için düzenledim .
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.
Bu sorunuza cevap veriyor mu?
İşlecin çalışma şekli, aynı anda artmasıdır, ancak bir değişkenten önce ise, ifade artan / azalan değişkenle değerlendirilir:
int x = 0; //x is 0
int y = ++x; //x is 1 and y is 1
Değişkenin peşindeyse, geçerli ifade, henüz artırılmamış / azaltılmamış gibi orijinal değişkenle yürütülür:
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
Gerekmedikçe, ön artış / azalış (++ x) kullanımında dcp ile hemfikirim. Gerçekten arttırma / azaltmayı kullandığım tek zaman, bu tür döngüler veya döngüler halindeyken. Bu döngüler aynıdır:
while (x < 5) //evaluates conditional statement
{
//some code
++x; //increments x
}
veya
while (x++ < 5) //evaluates conditional statement with x value before increment, and x is incremented
{
//some code
}
Dizileri dizine eklerken bunu da yapabilirsiniz:
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);
Vs vs...
Sadece kayıt için, C ++ 'da, eğer herhangi birini kullanabiliyorsanız (yani) işlemlerin sırasını umursamıyorsanız (sadece artırmak veya azaltmak ve daha sonra kullanmak istiyorsanız) ön ek operatörü daha verimlidir nesnenin geçici bir kopyasını oluşturmak zorunda. Ne yazık ki, çoğu kişi başlangıçta öğrendiğimiz şey olduğu için önek (++ var) yerine posfix (var ++) kullanır. (Bu konuda bir röportajda bana soruldu). Bu C # doğru olup olmadığından emin değilim, ama olacağını düşünüyorum.