C # neden önceki bir ifade olmadan {} kod bloklarına izin veriyor?


86

Neden C # izin vermez bir önceki açıklamada olmadan kod blokları (örn if, else, for, while)?

void Main()
{
    {   // any sense in this?
        Console.Write("foo");
    }
}

70
Herhangi bir sebebi var mı olmamalı ?
Jamiec

30
Ancak cevapların gösterdiği gibi, "incitmiyor, öyleyse izin verin" den daha fazla anlama sahip. Bu, bu tür sorular sormanın bir noktasıdır.
Seldon

8
+1 sorusu yeterince masum geliyor, ancak cevaplar bana gerçekten değerli bir şey öğretti
Nicolas78

7
@Akash: Neden diye sormadan asla daha iyi olamayacağız.
Richard

7
@Akash: Gözü pek elitist bir tavır gibi görünüyor. İnsanların her zaman soruları vardır ve nedenini sormak için bir neden yoksa, SO'ya sahip olmanın bir anlamı yoktur. Bu site, insanların acil sorunlarımızı çözmesi için değil (bu gerçekleşse de), hepimizin daha iyi programcılar olmamıza yardımcı olacak bir soru ve cevap havuzu sağlamak için. NEDEN sormak için SO! :-)
Richard

Yanıtlar:


90

Verdiğiniz bağlamda hiçbir önemi yok. Konsola sabit bir dize yazmak, program akışının herhangi bir yerinde aynı şekilde çalışacaktır. 1

Bunun yerine, genellikle bunları bazı yerel değişkenlerin kapsamını kısıtlamak için kullanırsınız. Bu, burada ve burada daha da detaylandırılmıştır . Bak João Angelo'nun cevap ve Chris Wallis 'cevabı kısa örnekler için. Aynısının C tarzı sözdizimine sahip diğer bazı diller için de geçerli olduğuna inanıyorum, ancak bu soruyla ilgili olmayacaklarından değil.


1 Tabii ki komik olmaya ve tamamen beklenmedik bir şey Consoleyapan bir Write()yöntemle kendi sınıfınızı yaratmaya karar vermedikçe.


24
Re: diğer diller: genellikle, ancak her zaman değil. JavaScript dikkate değer bir istisnadır; Belirli bir blokta yerel bir değişkenin bildirilmesi, değişkeni bloğun kapsamına almaz.
Eric Lippert

@EricLippert: C # 'da, bir blok içinde bir değişkenin bildirilmesi, değişkenin çalışma zamanı açısından kapsamının belirlenmesine neden olur mu? Anlayabildiğim kadarıyla, değişkenlerin yaşam süreleri genellikle kapsam blokları tarafından sınırlandırılmamaktadır; bu, bir döngüde bir değişkenle yapılan ilk şey onu bir outparametre olarak bir arayüz uygulamasına geçirmekse, karışık dilli projelerde gözlemlenebilir bir gerçektir. başka bir dilde ve bu uygulama değişkeni yazmadan önce okur.
supercat

Ve C ++ 'da, GC yerine RAII nedeniyle, çok daha kullanışlıdır.
Deduplicator

C ++ 'da, bir dene / yakala bloğu gibi davranır, bu nedenle bu kapsam içinde bildirilen değişkenler ve sınıflar, bu kapsamı terk ettiğinizde yığından çıkar. Bu, ad çakışmalarını önlemeye yardımcı olur ve işlevin bellek ayak izini azaltır. Ayrıca bu değişkenleri kod düzenleyicinin otomatik tamamlamasından da kaldırır. Genellikle dene / yakala bloklarını daha kullanışlı buluyorum.
Kit10

144

En { ... }azından yerel değişkenler için yeni bir kapsam getirme yan etkisine sahiptir.

Bunları, switchher durum için farklı bir kapsam sağlamak için ifadelerde kullanma eğilimindeyim ve bu şekilde, yerel değişkeni, kullanımlarının mümkün olan en yakın yerinde aynı isimle tanımlamama ve ayrıca bunların yalnızca vaka düzeyinde geçerli olduklarını belirtmeme izin verme eğilimindeyim .



6
Kasalarınızda dürbünlere ihtiyacınız varsa, bunlar çok büyüktür! Ekstrakt Yöntemi.
Jay Bazuzi 26:11

20
@Jay Bazuzi, birden fazla durumda aynı isimde yerel bir değişkene sahip olmak istemem onların çok büyük olması gerektiği anlamına gelmez. Sadece büyük sonuçlara varıyorsunuz ... :)
João Angelo

Harika Yanıt rozetiniz için tebrikler! :)
BoltClock

1
@BoltClock, teşekkürler, {}bu altın rozetlerin gelmesini sağlamak için birkaç soruya daha ihtiyacım var ... :)
João Angelo

56

Bu, kapsamı tanımlamak için parantez kullanan birçok C sözdizimi dilinin mantıksal bir yan etkisi olduğundan, C # 'ın bir özelliği değildir .

Örneğinizde parantezlerin hiçbir etkisi yoktur, ancak aşağıdaki kodda bir değişkenin kapsamını ve dolayısıyla görünürlüğünü tanımlarlar:

Bu , ilk blokta kapsam dışına çıktığım için izin verilir ve bir sonraki blokta tekrar tanımlanır:

{
    {
        int i = 0;
    }

    {
        int i = 0;
    }
}

Bu izin verilmez i kapsam dışında düşmüş ve artık dış kapsamında görünür olduğu gibi:

{
    {
        int i = 0;
    }

    i = 1;
}

Ve benzeri vb.


1
İngilizcenin çeşitli tatlarında köşeli parantez isimlendirmesindeki eşitsizlikleri okudum, ancak hangi tür {}parantez olarak bilinir?
BoltClock

İyi soru! Sanırım on yıl önce bir akıl hocam beynime yerleştirdi. Muhtemelen onlara 'küme parantezleri' veya 'kaşlı ayraçlar' demeliyim. Her biri kendi ... en.wikipedia.org/wiki/…
Chris Wallis

10
Sözlüğümde '(' = parantez, '{' = ayraç, '[' = köşeli parantez
pb.

Bir dakika, ben onlara küme parantezi derdim ve Wikipedia bu isimlendirmeyi içeriyor. Oxford İngilizce Sözlüğü bu parantez kullanımını şu şekilde tanımlar: One of two marks of the form [ ] or ( ), and in mathematical use also {}, used for enclosing a word or number of words, a portion of a mathematical formula, or the like, so as to separate it from the context; Her durumda parantez değiller, ancak 'kıvrık parantez' uygun görünüyor.
dumbledad

IME, "küme parantezleri" ve "köşeli parantezler".
cp.engr

18

{}Birkaç ifade içerebilen bir ifade olarak görüyorum .

Bir boole ifadesinin ardından gelen bir if ifadesini ve ardından gelen bir ifadeyi düşünün . Bu işe yarar:

if (true) Console.Write("FooBar");

Bu da işe yarar:

if (true)
{
  Console.Write("Foo");
  Console.Write("Bar");
}

Yanılmıyorsam buna blok ifade denir.

Yana {}diğer ifadeler içerebilir ayrıca diğer içerebilir {}. Bir değişkenin kapsamı ebeveyni tarafından tanımlanır {}(blok ifadesi).

Bahsetmeye çalıştığım nokta, bu {}sadece bir ifade, yani bir eğer ya da herneyse gerektirmiyor ...


+1 C-stili dillerde küme parantezleri tam olarak budur - sözde "bileşik ifade".
Michael Ekstrand

12

C-sözdizimi dillerinde genel kural "aradaki { }her şey tek bir ifade olarak ele alınmalıdır ve tek bir ifadenin yapabileceği her yere gidebilir" dir:

  • Bir if.
  • A for, whileveya do.
  • Kodun herhangi bir yerinde .

Tüm niyet ve amaçlar için, dil dilbilgisi şunları içeriyordu:

     <statement> :== <definition of valid statement> | "{" <statement-list> "}"
<statement-list> :== <statement> | <statement-list> <statement>

Yani, "bir ifade (çeşitli şeyler) veya bir açılış parantezinden, ardından bir ifade listesi (bir veya daha fazla ifade içerebilir) ve ardından kapalı bir parantezden oluşabilir". IE "bir { }blok herhangi bir yerde herhangi bir ifadenin yerini alabilir". Kodun ortasına dahil.

{ }Tek bir ifadenin gidebileceği herhangi bir yere bir bloğa izin vermemek , aslında dil tanımını daha karmaşık hale getirirdi .


Birisi bu cevabı yeni yükseltti (9 yıl sonra), bu aslında bu soruya özel bir cevap değildi, çok daha genel bir tartışma. Dil ve kütüphaneler pekâlâ yerini almış olabilir .. Ama yine de bir zevkti, teşekkürler.
Massimo

1

Çünkü C ++ (ve java), önceki bir ifade olmadan kod bloklarına izin verdi.

C ++ onlara izin verdi çünkü C bunu yaptı.

Tüm bunların Avrupa program dili ( Modula-2 tabanlı) tasarımından ziyade ABD program dili (C tabanlı) tasarımının kazandığı gerçeğine bağlı olduğunu söyleyebilirsiniz .

(Kontrol ifadeleri tek bir ifadeye göre hareket eder, ifadeler yeni ifadeler oluşturmak için gruplar olabilir)


Modül2 mi yoksa Modula2 mi demek istediniz?
Richard Ev

Doğrusu bu doğru cevaptır. Ayrıca, "Çünkü her bilgisayar dili yapar"
Şişko


0

1 Çünkü ... İfadenin Kapsam Alanını Korur .. veya İşlev, Bu, büyük kod için gerçekten yararlıdır ..

{
    {
        // Here this 'i' is we can use for this scope only and out side of this scope we can't get this 'i' variable.

        int i = 0;
    }

    {
        int i = 0;
    }
}

görüntü açıklamasını buraya girin


0

C # 'nın ifadelerden önce gelen kod bloklarına neden izin verdiğini sordunuz. "Neden" sorusu, "bu yapının olası faydaları neler olabilir?" Şeklinde de yorumlanabilir.

Şahsen, kod bloğunun yerel değişkenlerin kapsamını sınırladığını unutmadan, okunabilirliğin diğer geliştiriciler için büyük ölçüde geliştirildiği C # 'da ifadesiz kod blokları kullanıyorum. Örneğin, ek kod blokları sayesinde okunması çok daha kolay olan aşağıdaki kod parçacığını düşünün:

OrgUnit world = new OrgUnit() { Name = "World" };
{
    OrgUnit europe = new OrgUnit() { Name = "Europe" };
    world.SubUnits.Add(europe);
    {
        OrgUnit germany = new OrgUnit() { Name = "Germany" };
        europe.SubUnits.Add(germany);

        //...etc.
    }
}
//...commit structure to DB here

Bunun her yapı seviyesi için yöntemler kullanılarak daha zarif bir şekilde çözülebileceğinin farkındayım. Ancak yine de, örnek veri tohumlayıcıları gibi şeylerin genellikle hızlı olması gerektiğini unutmayın.

Dolayısıyla, yukarıdaki kod doğrusal olarak çalıştırılsa bile, kod yapısı nesnelerin "gerçek dünya" yapısını temsil eder, böylece diğer geliştiricilerin anlamasını, sürdürmesini ve genişletmesini kolaylaştırır.

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.