Neden ifade (j ++); yasak?


169

Aşağıdaki kod yanlış ( ideone'de bakınız ):

public class Test
{
    public static void Main()
    {
        int j = 5;
        (j++);      // if we remove the "(" and ")" then this compiles fine.
    }
}

hata CS0201: Yalnızca atama, çağrı, arttırma, azaltma, bekletme ve yeni nesne ifadeleri ifade olarak kullanılabilir

  1. Parantezleri kaldırdığımızda kod neden derleniyor?
  2. Neden parantez ile derlenmiyor?
  3. C # neden bu şekilde tasarlandı?

29
@ C # dil tasarımı ile ilgili çok sayıda insan SO üzerinde, bu yüzden sordum bu yüzden. Bunda yanlış bir şey mi var?
user10607

34
"Belirli bir programlama dili neden bu davranışı bu şekilde ele alıyor?"
Mage Xy

20
Şimdi Eric Lippert'in bir cevabı var. Belki kabul edilen cevap hakkındaki kararınızı yeniden düşünmek istersiniz. Noel, bu yüzden belki de cevabı çok erken kabul ettin.
Thomas Weller

17
@Servy Tasarım kararlarının asla belgelenmediğini ve herkes tarafından bilinmediğini mi ima ediyorsunuz? O ediyor değil bu onun bir tahmin soruyor anlamına gelmez - o bir cevap soruyor, tahmin etmek SO kullanmamalarını istiyoruz. İnsanların bir tahminle cevap verip vermedikleri , onlar değil. OP belirttiği gibi, oradaki olan yığın taşması insanlar yaptılar C # aslında çalışma ve bu kararları yaptı.
Rob

5
@Rob: Sorun şu ki, evet, gerekçe zaten bir yerde belgelenmedikçe, zorunluluk ama spekülasyon eğlenceli ve kim kendi paylaşmak istemiyor? Bu tür saf (veya "eğitimli") tahminlerin güvenilir bir şekilde kaldırıldığından emin olmanın bir yolunu bulursanız, bana söyleyin, bir servet kazanacağız.
Tekilleştirici

Yanıtlar:


221

Derin anlayışlar takdir edildi.

Elimden geleni yapacağım.

Diğer cevaplar belirttiği gibi, burada ne oluyor derleyici bir o algıladığını olduğu ifade bir şekilde kullanılıyor açıklamada . Birçok dilde - C, JavaScript ve diğerleri - bir ifadeyi ifade olarak kullanmak tamamen yasaldır. 2 + 2;etkisi olmayan bir ifade olmasına rağmen bu dillerde yasaldır. Bazı ifadeler yalnızca değerleri için yararlıdır, bazı ifadeler yalnızca yan etkileri (faydalı bir geri dönüş yöntemine çağrı gibi) için yararlıdır ve bazı ifadeler maalesef her ikisi için de yararlıdır. (Artış gibi.)

Nokta: sadece ifadelerden oluşan ifadeler, bu ifadelerin tipik olarak yan etkileri için değerlerinden daha yararlı olduğu düşünülmedikçe neredeyse kesinlikle hatalardır . C # tasarımcıları, genellikle yan etkileri olarak düşünülen ifadelere izin verirken, tipik olarak değerleri için yararlı olduğu düşünülenlere izin vermeyerek orta bir zemin bulmak istiyorlardı. C # 1.0'da tanımladıkları ifade kümesi, artışlar, azalmalar, yöntem çağrıları, ödevler ve biraz tartışmalı olarak yapıcı çağrılarıydı.


ASIDE: Normalde bir nesne yapısının, yapının yan etkisi için değil, ürettiği değer için kullanıldığı düşünülmektedir; benim görüşüme göre izin vermek new Foo();biraz yanlıştır. Özellikle, bir güvenlik hatasına neden olan gerçek kodda bu kalıbı gördüm:

catch(FooException ex) { new BarException(ex); } 

Kod karmaşıksa bu kusuru tespit etmek şaşırtıcı derecede zor olabilir.


Derleyici, bu nedenle, listede olmayan ifadelerden oluşan tüm ifadeleri algılamaya çalışır. Özellikle, parantez içindeki ifadeler sadece - parantez içindeki ifadeler olarak tanımlanır. "İfade ifadesi olarak izin verilir" listesinde yer almazlar, bu nedenle izin verilmez.

Bütün bunlar C # dilinin tasarım prensibine hizmet ediyor. Eğer yazdıysanız (x++);muhtemelen yanlış bir şey yapıyordunuz . Bu muhtemelen bir yazım hatası M(x++);ya da adil bir şeydir. C # derleyicisi ekibinin tutum hatırla değil " biz bu işi yapmak için bazı yollar bulabilir? " C # derleyicisi ekibinin tutum "olduğu bir olasılıkla hata gibi makul kod görünüyor, izin verirsen geliştiricisi bilgilendirmek ". C # geliştiricileri bu tutumu sever.

Şimdi, bütün bu dedi, aslında C # şartname birkaç tuhaf durumlar vardır mu ima veya parantez izin verilmeyen ancak C # derleyicisi zaten onları tanır edilir düpedüz devlet. Hemen hemen tüm bu durumlarda, belirtilen davranış ve izin verilen davranış arasındaki küçük tutarsızlık tamamen zararsızdır, bu nedenle derleyici yazarları bu küçük hataları asla düzeltmemiştir. Bunları burada okuyabilirsiniz:

Return myVar ve return (myVar) arasında fark var mı?


5
Re: "Bir inşaatçı çağrısı normalde inşaatın yan etkisi için değil, ürettiği değer için kullanılan olarak düşünüyor; Bence bu biraz yanlış bir özellik": Bu kararda bir faktör hayal ediyorum derleyici bunu yasakladı, sen durumlarda herhangi temiz düzeltme olmaz olmasıydı olan yan etkisi olarak nitelendirdiler. (Diğer yasak ifadelerin çoğunda, amaca hizmet etmeyen ve bunun yerine ... ? ... : ..., düzeltmenin kullanılacağı if/ elsebunun yerine kaldırılabileceği yabancı bölümler bulunur .)
Aralık'ta

1
@ruakh: Bu, caydırılması gereken bir davranış olduğundan, makul / ucuz / basit bir düzeltme olduğu sürece temiz bir düzeltme gerekli değildir. Hangisi var; bir değişkene atayın ve bu değişkeni kullanmayın. Kullanmadığınızdan emin olmak istiyorsanız, o kod satırına kendi kapsamını verin. Teknik olarak, kodun anlambilimini değiştirdiği iddia edilebilir (işe yaramaz bir referans ataması hala işe yaramaz bir referans atamasıdır), pratikte önemli değildir. Biraz farklı IL ürettiğini itiraf ediyorum ... ama sadece optimizasyon olmadan derlendiğinde.
Brian

Safari, Firefox ve Chrome, yazarken ReferenceError verir contineu;.
Brian McCutchon

2
@McBrainy: Haklısın. Yanlış yazımdan kaynaklanan kusuru yanlış hatırlıyorum; Notlarımı kontrol edeceğim. Bu arada, buradaki daha büyük noktaya almanca olmadığı için rahatsız edici ifadeyi sildim.
Eric Lippert

1
@Mike: Katılıyorum. Bazen ifadeyi gördüğümüz bir başka durum, test senaryolarıdır, try { new Foo(null); } catch (ArgumentNullException)...ancak açıkçası bu durumlar tanım gereği üretim kodu değildir. Bu tür bir kodun sahte bir değişkene atamak için yazılabileceği makul görünmektedir.
Eric Lippert

46

In C # dili şartname

İfade ifadeleri ifadeleri değerlendirmek için kullanılır. İfadeler olarak kullanılabilen ifadeler, yöntem çağrılarını, yeni operatörü kullanan nesne tahsislerini, = kullanan bileşik atamalarını ve bileşik atama operatörlerini, ++ ve - operatörlerini kullanarak arttırma ve azaltma işlemlerini içerir ve ifadeleri bekler.

Parantezleri bir ifadenin etrafına koymak, parantez içine alınmış yeni bir ifade oluşturur. Şartname:

Parantez içindeki ifade, parantez içine alınmış bir ifadeden oluşur. ... Parantez içindeki ifade, parantez içindeki ifade değerlendirilerek değerlendirilir. Parantez içindeki ifade bir ad alanını veya türü belirtirse, derleme zamanı hatası oluşur. Aksi takdirde, parantez içindeki ifadenin sonucu, içerilen ifadenin değerlendirilmesinin sonucudur.

Parantez içindeki ifadeler geçerli bir ifade ifadesi olarak listelenmediğinden, spesifikasyona göre geçerli bir ifade değildir. Tasarımcılar neden bu şekilde yapmayı seçtiler kimsenin tahminidir, ancak bahse girerim, tüm deyim parantez içinde yer alıyorsa parantezin işe yaramadığıdır: stmtve (stmt)tamamen aynıdır.


4
@Servy: Eğer yakından okursanız, bundan biraz daha incelikliydi. "İfade İfadesi" gerçekten geçerli bir ifadedir ve şartname geçerli ifadeler olabilen ifade türlerini listeler. Ancak, "parantezli ifade" olarak adlandırılan ifade türünün geçerli ifade ifadeleri olarak kullanılabilen geçerli ifadeler listesinde DEĞİLDİR.
Frank Bryce

4
OPDil tasarımı hakkında hiçbir şey istiyor. Sadece bunun neden bir hata olduğunu bilmek istiyor. Cevap: geçerli bir ifade olmadığı için .
Leandro

9
Tamam, benim hatam. Cevap: çünkü, spesifikasyona göre , geçerli bir ifade değildir. İşte burada: bir tasarım nedeni!
Leandro

3
Soru, dilin neden bu sözdizimini bu şekilde ele almak için tasarlandığına dair derin, tasarım odaklı bir neden istemiyor - bir kod parçası başka bir kod parçası (yeni başlayanlara davranması gerektiği gibi) neden derlendiğini soruyor özdeş) derleme başarısız. Bu gönderi buna cevap veriyor.
Mage Xy

4
@Servy JohnCarpenter sadece "Bunu yapamazsın" demiyor. Diyor ki, karıştırdığınız bu iki şey aynı değil. j ++ bir İfade Deyimi, (j ++) ise parantez içindeki bir ifadedir. Aniden OP şimdi farkı ve ne olduklarını biliyor. Bu iyi bir cevap. Başlığının değil sorusunun bedenini cevaplar. Sorunun başlığındaki "tasarım" kelimesinden çok fazla çekişme olduğunu düşünüyorum, ancak bunun sadece teknik özelliklerden toplanan tasarımcılar tarafından cevaplanması gerekmiyor.
thinklarge

19

beacause etrafında parantez i++bir ifade oluşturmak / tanımlamak .. hata mesajının dediği gibi .. basit bir ifade bir ifade olarak kullanılamaz.

dil neden bu şekilde olacak şekilde tasarlandı? kod olarak yan etkisi olmayan, ifadeler olarak yanıltıcı ifadelere sahip olan hataların önlenmesi

int j = 5;
j+1; 

ikinci satırın bir etkisi yoktur (ancak fark etmemiş olabilirsiniz). Ancak derleyici onu kaldırmak yerine (kod gerekli olmadığından) .it açıkça kaldırmanızı ister (böylece farkında olursunuz veya hata olur) VEYA bir şey yazmayı unuttuğunuzda düzeltin.

düzenleme :

örgülü ile ilgili parçayı daha net hale getirmek için c # 'daki parantezler (döküm ve işlev çağrısı gibi diğer kullanımların yanı sıra), ifadeleri gruplandırmak ve tek bir ifadeyi (alt ifadelerin markası) döndürmek için kullanılır.

bu kod düzeyinde yalnızca açıklamalara izin verilir.

j++; is a valid statement because it produces side effects

ama parantezleri kullanarak onu ifade olarak

myTempExpression = (j++)

ve bu

myTempExpression;

Derleyici ifadeyi yan etki olarak sağlayamadığından geçerli değil. (durma problemine girmeden değil) ..


Evet, ilk başta ben de öyle düşünmüştüm. Ama bu yaptığı bir yan etkisi vardır. jDeğişken sonrası artış yapar mı?
user10607

1
j++;geçerli bir ifadedir, ancak parantezleri kullanarak söylüyorsunuz let me take this stement and turn it into an expression.. ve ifadeler koddaki bu noktada geçerli değildir
CaldasGSM

Kodun bir istisna atmadan bir değerin hesaplanabileceğini iddia etmek isteyebileceği, ancak bu şekilde hesaplanan gerçek değeri umursamadığı için "compute and ignore" ifadesinin bir formu yoktur. Hesapla ve yoksay ifadesi çok sık kullanılmaz, ancak bu gibi durumlarda programcının niyetini netleştirir.
supercat
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.