Const parametrelerine C # 'da neden izin verilmiyor?


102

Özellikle C ++ geliştiricileri için garip görünüyor. C ++ ' constda, durumunun yöntemde değişmeyeceğinden emin olmak için bir parametreyi işaretlerdik . const refRef ile geçmek ve durumun değişmeyeceğinden emin olmak gibi C ++ 'ya özgü başka nedenler de vardır . Ama neden C # 'da yöntem parametreleri sabiti olarak işaretleyemiyoruz?

Yöntemimi neden aşağıdaki gibi açıklayamıyorum?

    ....
    static void TestMethod1(const MyClass val)
    {}
    ....
    static void TestMethod2(const int val)
    {}
    ....

C ++ 'da her zaman sadece bir güvenlik yakalama özelliğiydi ve benim gördüğüm kadarıyla hiçbir zaman dille gerçek anlamda bütünleşmedi. C # devs, çok fazla değer kattığını düşünmedi.
Noldorin

3
Bu soruda daha büyük bir tartışma: "c #
sabit

Değer türleri [çıkış / ref] için vardır, ancak başvuru türleri yoktur. Bu ilginç bir soru.
kenny

4
Bu soru nasıl hem C # hem de dilden bağımsız etiketlere sahip olabilir?
CJ7

1
Değişmez veriler ve yan etkileri olmayan işlevler hakkında akıl yürütmek daha kolaydır. F # fsharpforfunandprofit.com/posts/is-your-language-unreasonable
Colonel Panic

Yanıtlar:


59

Diğer iyi cevaplara ek olarak, C-stili sabitliği C # 'a koymamak için başka bir neden daha ekleyeceğim. Dedin:

yöntemde durumunun değişmeyeceğinden emin olmak için parametreyi const olarak işaretleriz.

Const gerçekten bunu yapsaydı, bu harika olurdu. Const bunu yapmaz. Sabit bir yalan!

Const gerçekten kullanabileceğime dair hiçbir garanti vermiyor. Sabit bir şey alan bir yönteminiz olduğunu varsayalım. İki kod yazarı vardır: arayanı yazan kişi ve arayan ucu yazan kişi . Aranan ucun yazarı, yöntemin bir sabit almasını sağlamıştır. İki yazar neyin nesne hakkında değişmez olduğunu varsayabilir?

Hiçbir şey değil. Aranan uç, const'ı atmak ve nesneyi değiştirmek için serbesttir, bu nedenle arayan, bir const alan bir yöntemi çağırmanın onu değiştirmeyeceğinin garantisine sahip değildir. Benzer şekilde, aranan uç, nesnenin içeriklerinin aranan ucun eylemi boyunca değişmeyeceğini varsayamaz; aranan uç , const nesnesinin const olmayan bir diğer adı üzerinde bazı mutasyon yöntemlerini çağırabilirdi ve şimdi sözde const nesnesi değişti .

C-style const, nesnenin değişmeyeceğine ve dolayısıyla bozulacağına dair hiçbir garanti vermez. Şimdi, C zaten zayıf bir tür sisteme sahip, burada gerçekten istiyorsanız double türünün int'e yeniden yorumlanmasını sağlayabilirsiniz, bu nedenle const'a göre zayıf bir tür sisteme sahip olması şaşırtıcı olmamalıdır. Ancak C # iyi bir tür sistemine sahip olacak şekilde tasarlanmıştır , "bu değişken bir dize içerir" dediğinizde değişkenin aslında bir dizeye (veya boş) bir başvuru içerdiği bir tür sistemi . Yazım sistemine kesinlikle bir C-stili "const" değiştiricisi koymak istemiyoruz çünkü yazı sisteminin yalan olmasını istemiyoruz . Kodunuz hakkında doğru şekilde düşünebilmeniz için tür sisteminin güçlü olmasını istiyoruz .

Const in C bir kılavuzdur ; temelde "bu şeyi değiştirmeye çalışmama konusunda bana güvenebilirsin" anlamına gelir. Bu tür sisteminde olmamalıdır ; tip sistemindeki şeyler , kullanımıyla ilgili bir kılavuz değil, akıl yürütebileceğiniz nesne hakkında bir gerçek olmalıdır .

Şimdi, beni yanlış anlamayın; C'deki const'in derinden kırılmış olması, tüm kavramın işe yaramaz olduğu anlamına gelmez. Görmek istediğim şey , C # 'da "const" ek açıklamasının gerçekten doğru ve yararlı bir biçimidir; bu, hem insanların hem de derleyicilerin kodu anlamalarına yardımcı olmak için kullanabilecekleri ve çalışma zamanının otomatik paralelleştirme gibi şeyler yapmak için kullanabileceği bir ek açıklama ve diğer gelişmiş optimizasyonlar.

Örneğin, bir kod parçasının etrafına "bir kutu çizebildiğinizi" ve derleyici tarafından kontrol edilebilecek bir şekilde "Bu kod parçasının bu sınıfın hiçbir alanında mutasyon yapmayacağını garanti ediyorum" diyebildiğinizi hayal edin . Veya "bu saf yöntem nesnenin iç durumunu değiştirir, ancak kutunun dışında hiçbir şekilde gözlemlenemez " yazan bir kutu çizin . Böyle bir nesne otomatik olarak güvenli bir şekilde çoklu iş parçacıklı olamaz, ancak otomatik olarak hafızaya alınabilir . Zengin optimizasyonları ve daha derin anlayışı mümkün kılacak koda koyabileceğimiz her türlü ilginç ek açıklama vardır. Zayıf C-stili sabit açıklamasından çok daha iyisini yapabiliriz.

Ancak bunun sadece spekülasyon olduğunu vurguluyorum . Bu tür bir özelliği herhangi bir varsayımsal gelecek C # sürümüne koymak için kesin bir planımız yok, eğer varsa, öyle ya da böyle açıklamadık. Bu, görmeyi çok istediğim bir şey ve çok çekirdekli bilgi işlem üzerine gelecek vurgunun gerektirebileceği bir şey, ancak bunların hiçbiri, herhangi bir özelliğin veya C # için gelecek yönün bir tahmini veya garantisi olarak yorumlanmamalıdır.

Şimdi, eğer istediğiniz şey yerel değişken üzerinde "bu parametrenin değeri yöntem boyunca değişmez" diyen bir parametre olan bir açıklama ise, o zaman bu kolayca yapılabilir. Bir kez başlatılacak "salt okunur" yerelleri ve parametreleri ve yöntemde değişiklik yapmak için bir derleme zamanı hatasını destekleyebiliriz. "Using" ifadesiyle bildirilen değişken zaten yereldir; değişkenleri "kullanıyor" gibi davranmalarını sağlamak için tüm yerellere ve parametrelere isteğe bağlı bir açıklama ekleyebiliriz. Asla çok yüksek öncelikli bir özellik olmadı, bu yüzden hiç uygulanmadı.


34
Üzgünüm ama bu argümanı çok zayıf buluyorum, bir geliştiricinin yalan söylemesi hiçbir dilde engellenemez. a nesnesini değiştiren void foo (const A & a), int sayımlarından farklı değildir Armut sayısını döndüren elma (Sepet b). Bu sadece bir bug, herhangi bir dilde derlenen bir bug.
Alessandro Teruzzi

55
“Aranan uç, konstü atmakta özgürdür…” uhhhhh… (° _ °) Bu, burada yaptığınız oldukça sığ bir argüman. Aranan uç, rastgele bellek konumlarını yazmaya başlamak için de ücretsizdir 0xDEADBEEF. Ancak her ikisi de çok kötü programlama olur ve herhangi bir modern derleyici tarafından erken ve dokunaklı bir şekilde yakalanır. Gelecekte cevap yazarken, lütfen bir dilin arka kapılarını kullanarak teknik olarak mümkün olanı gerçek gerçek dünya kodunda uygulanabilir olanlarla karıştırmayın. Bunun gibi çarpık bilgiler, daha az deneyimli okuyucuların kafasını karıştırır ve SO'daki bilgilerin kalitesini düşürür.
Slipp D. Thompson

8
"Const in C bir kılavuzdur;" Söylediğiniz bazı şeyler için bir kaynağa atıfta bulunmak, davanıza gerçekten yardımcı olacaktır. Eğitimim ve endüstri deneyimimde, alıntı yapılan ifade hogwash'dır - C'deki const, tıpkı tip sistemin kendisi kadar zorunlu yerleşik özelliktir - her ikisinin de gerektiğinde onları aldatmak için arka kapıları vardır (aslında C'deki her şey gibi) ancak beklenir kitap tarafından kodun% 99,99'unda kullanılacak.
Slipp D. Thompson

29
Bu cevap, bazen C # tasarımından nefret etmemin sebebidir. Dil tasarımcıları, diğer geliştiricilerden çok daha akıllı olduklarından kesinlikle eminler ve onları hatalardan aşırı derecede korumaya çalışıyorlar. Açıktır ki, const anahtar sözcüğü yalnızca derleme zamanında çalışır, çünkü C ++ 'da belleğe doğrudan erişimimiz vardır ve istediğimiz her şeyi yapabilir ve yuvarlak const bildirimi elde etmek için çeşitli yollar vardır. Ama bunu normal durumlarda kimse yapmaz. Bu arada, C # 'da' özel 've' korumalı 'da hiçbir garanti sağlamaz, çünkü bu yöntemlere veya alanlara yansıma kullanarak erişebiliriz.
BlackOverlord

13
@BlackOverlord: (1) Özellikleri geliştiricileri başarısızlığa değil, doğal olarak başarıya götüren bir dil tasarlama arzusu , sizin varsayımınıza göre tasarımcıların müşterilerinden daha akıllı oldukları inancıyla değil, yararlı araçlar oluşturma arzusuyla motive edilir . (2) Yansıma, C # dilinin bir parçası değildir; çalışma zamanının bir parçasıdır; yansımaya erişim, çalışma zamanının güvenlik sistemiyle sınırlıdır. Düşük güven koduna özel yansıtma yapma yeteneği verilmez. Garantiler erişim değiştiricileri tarafından sağlanan içindir düşük güven kodu ; yüksek güven kodu her şeyi yapabilir.
Eric Lippert

24

C # 'da const doğruluğu olmamasının nedenlerinden biri , çalışma zamanı düzeyinde mevcut olmamasıdır. C # 1.0'ın, çalışma zamanının bir parçası olmadığı sürece herhangi bir özelliğe sahip olmadığını unutmayın.

Ve CLR'nin sabit doğruluk kavramına sahip olmamasının birkaç nedeni örneğin:

  1. Çalışma zamanını karmaşıklaştırır; ayrıca, JVM'de de yoktu ve CLR temelde C ++ benzeri bir çalışma zamanı değil, JVM benzeri bir çalışma zamanı oluşturmak için bir proje olarak başladı.
  2. Çalışma zamanı düzeyinde const doğruluğu varsa, BCL'de const doğruluğu olmalıdır, aksi takdirde özellik .NET Framework söz konusu olduğunda hemen hemen anlamsızdır.
  3. BCL const doğruluğunu gerektiriyorsa Ama CLR üstündeki her dil const doğruluğunu desteklemelidir (VB, JavaScript, Python, Ruby, F #, vs.) en That değil ne olacak.

Sabit doğruluk, hemen hemen yalnızca C ++ 'da bulunan bir dil özelliğidir. Bu nedenle, CLR'nin neden kontrol edilmiş istisnalar gerektirmediğine (yalnızca Java diline özgü bir özellik olan) ilişkin aynı argümantasyona dayanır.

Ayrıca, geriye dönük uyumluluğu bozmadan yönetilen bir ortamda bu kadar temel bir sistem özelliği sunabileceğinizi sanmıyorum. Bu yüzden C # dünyasına girerken sabit doğruluğa güvenmeyin.


JVM'nin sahip olmadığından emin misiniz? Bildiğim kadarıyla var. Java'da genel statik void TestMethod'u (final int val) deneyebilirsiniz.
Incognito

2
Final gerçekten sabit değil. Değerin / referansın kendisini değil, referans IIRC üzerindeki alanları yine de değiştirebilirsiniz. (Zaten değere göre iletilir, bu nedenle parametre değerini değiştirmenizi önlemek için daha çok bir derleyici numarasıdır.)
Ruben

1
3. merminiz yalnızca kısmen doğrudur. BCL çağrıları için const parametrelerine sahip olmak, yalnızca sözleşmeyi daha kesin bir şekilde tanımladıkları için önemli bir değişiklik olmayacaktır. "Bu yöntem nesnenin durumunu değiştirmeyecek", "Bu yöntem bir sabit değeri geçmenizi gerektiriyor" un aksine
kırılacak

2
Yöntemin içinde zorunlu kılınmıştır , böylece onu BCL'ye sokmak için bir değişiklik olmaz.
Rune FS

1
Çalışma zamanı onu zorlayamasa bile, bir fonksiyonun bir refparametreye yazmasına izin verilip verilmeyeceğini / beklenip beklenmeyeceğini belirten bir özniteliğe sahip olmak yararlı olacaktır (özellikle, struct yöntemleri / özellikleri durumunda this). Bir yöntem özellikle bir refparametreye yazmayacağını belirtirse , derleyici salt okunur değerlerin geçirilmesine izin vermelidir. Tersine, bir yöntem yazacağını belirtirse this, derleyici böyle bir yöntemin salt okunur değerlerde çağrılmasına izin vermemelidir.
supercat

12

C # 'nin sabit doğru olmamasının iki nedeni olduğuna inanıyorum.

Birincisi anlaşılabilirliktir . Çok az C ++ programcısı const-doğruluğunu anlar. Bunun basit örneği const int argsevimli, ama ben de gördüm char * const * const arg- sabit olmayan karakterlere sabit işaretçiler için sabit bir işaretçi. İşlevlere işaretçilerdeki sabit doğruluk tamamen yeni bir gizleme düzeyidir.

İkincisi, sınıf bağımsız değişkenlerinin değer tarafından iletilen başvurular olmasıdır. Bu, açıkça anlaşılır bir sözdizimi olmadan başa çıkılması gereken iki sabitlik düzeyi olduğu anlamına gelir . Benzer bir tökezleme noktası da koleksiyonlardır (ve koleksiyon koleksiyonları vb.).

Sabit-doğruluk, C ++ tipi sistemin önemli bir parçasıdır. Teoride C # 'a yalnızca derleme zamanında kontrol edilen bir şey olarak eklenebilir (CLR'ye eklenmesi gerekmez ve const üye yöntemleri kavramı dahil edilmedikçe BCL'yi etkilemez) .

Bununla birlikte, bunun olası olmadığına inanıyorum: ikinci nedeni (sözdizimi) çözmek oldukça zor olacaktır, bu da ilk nedeni (anlaşılabilirliği) daha da bir problem haline getirecektir.


1
Birini kullanabilirsiniz olarak CLR gerçekten bu konuda endişe gerek olmadığını haklısın modoptve modreq(C + / CLI zaten yaptığı gibi - bkz bu bilgi depolamak için meta veri düzeyde System.Runtime.CompilerServices.IsConst); ve bu önemsiz bir şekilde const yöntemlerine de genişletilebilir.
Pavel Minaev

Zahmete değer, ancak tip güvenli bir şekilde yapılması gerekiyor. Bahsettiğiniz Deep / Shallow const, bir kutu solucan açar.
user1496062

Referansların gerçekten manipüle edildiği bir c ++ 'da, iki tür const'a sahip olmakla ilgili argümanınızı görebilirim. Bununla birlikte, C # 'da ("işaretçileri" kullanmak için arka kapılardan geçmeniz gereken), referans türleri (yani sınıflar) için iyi tanımlanmış bir anlam ve değer için farklı olsa da iyi tanımlanmış bir anlam olduğu bana yeterince açık görünüyor. türler (ör. ilkeller, yapılar)
Assimilater

2
Yapılandırmayı anlayamayan programcılar C ++ ile programlama yapmamalıdır.
Steve White

5

constC # 'da "derleme zamanı sabiti" anlamına gelir, C ++' da olduğu gibi "salt okunur, ancak muhtemelen başka kodla değiştirilebilir" anlamına gelir. constC # 'da kabaca bir C ++ benzeri readonly, ancak bu yalnızca alanlar için geçerlidir. Bunun dışında, C # 'ta C ++ benzeri const doğruluğu kavramı yoktur.

Mantığın kesin olarak söylenmesi zor, çünkü birçok potansiyel neden var, ancak benim tahminim, dili her şeyden önce basit tutma arzusu ve bu ikinciyi uygulamanın belirsiz avantajları olacaktır.


Yani MS'in yöntemlerde const parametrelere sahip olmayı 'gürültü' olarak gördüğünü düşünüyorsunuz.
Incognito

1
"Gürültünün" ne olduğundan emin değilim - ben buna "yüksek maliyet / fayda oranı" demeyi tercih ederim. Ama elbette, emin olmak için C # ekibinden birine ihtiyacınız olacak.
Pavel Minaev

Anladığım kadarıyla, senin argüman, sabitliğin basit tutmak için C # dışında bırakılmış olmasıdır. Bunu bir düşün.
Steve White

2

Bu, C # 7.2'den (Visual Studio 2017 15.5 ile Aralık 2017) itibaren mümkündür.

Yalnızca Yapılar ve temel türler için! , sınıf üyeleri için değil.

inBağımsız değişkeni başvuruya göre girdi olarak göndermek için kullanmalısınız . Görmek:

Bakınız: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-parameter-modifier

Örneğiniz için:

....
static void TestMethod1(in MyStruct val)
{
    val = new MyStruct;  // Error CS8331 Cannot assign to variable 'in MyStruct' because it is a readonly variable
    val.member = 0;  // Error CS8332 Cannot assign to a member of variable 'MyStruct' because it is a readonly variable
}
....
static void TestMethod2(in int val)
{
    val = 0;  // Error CS8331 Cannot assign to variable 'in int' because it is a readonly variable
}
....
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.