Neden C # ile 'using' direktifini kullanmıyorsun?


71

Büyük bir C # projesinde mevcut kodlama standartları, 'tür' direktifinin kullanılmasını yasaklayan, tüm tür adlarının tam olarak nitelendirilebileceği kuralını içerir. Yani, tanıdık değil:

using System.Collections.Generic;

.... other stuff ....

List<string> myList = new List<string>();

(Muhtemelen varde yasak olması sürpriz değildir .)

Sonunda:

System.Collections.Generic.List<string> myList = new System.Collections.Generic.List<string>();

Bu, yazımda% 134'lük bir artış, hiçbirinde faydalı bilgi sağlanmadı. Benim düşünceme göre, artışın% 100'ü aslında anlayışı engelleyen gürültüdür (karışıklık) .

30+ yıllık programlamada, bir ya da iki kez önerilen ancak asla uygulanmayan bir standart gördüm. Arkasındaki mantık benden kaçıyor. Standardı uygulayan kişi aptal değildir ve kötü niyetli olduğunu düşünmüyorum. Bir şey eksik olmadıkça, bu tek alternatif olarak yanlış giden bir şey.

Hiç böyle bir standardın uygulandığını duydunuz mu? Eğer öyleyse, arkasındaki sebep neydi? usingBu kişiyi bu yasağı kaldırmaya ikna edebilecek "aptal" veya "herkes işe alır " dışındaki argümanları düşünebilir misiniz ?

muhakeme

Bu yasağın nedenleri şunlardı:

  1. Tam türünü elde etmek için fareyi adın üzerine getirmeniz çok zordur. Tam nitelikli türün her zaman her zaman görünür olması daha iyidir.
  2. E-postayla gönderilen kod parçacıkları tam olarak nitelenmiş bir ada sahip değildir ve bu nedenle anlaşılması zor olabilir.
  3. Kodu Visual Studio'nun dışında (örneğin Notepad ++) görüntülerken veya düzenlerken, tam tür adını almak mümkün değildir.

Benim iddiam, üç vakanın da nadir olması ve herkesin sadece birkaç nadir vakayı barındırabilmesi için darmadağın ve daha az anlaşılabilir bir kodun bedelini ödemesinin yanlış yapılmasıdır.

Öncelikli mesele olmayı umduğum olası ad alanı çatışması sorunlarından bile söz edilmedi. Bu özellikle şaşırtıcı, çünkü MyCompany.MyProject.Coreözellikle kötü bir fikir olan bir ad alanımız var . Uzun zaman önce bir şeyi Systemya Coreda C # ile isimlendirmenin deliliğin hızlı bir yolu olduğunu öğrendim .

Diğerlerinin de belirttiği gibi, ad alanı çatışmaları yeniden düzenleme, ad alanı takma adları veya kısmi yeterlilikle kolayca yapılabilir.


Yorumlar uzun tartışmalar için değildir; bu konuşma sohbete taşındı .
maple_shaft

1
: O (ama C ++ Dünya cinsinden) iyi bir fikir olabilir neden bir gerçek dünyadaki örneği bir cevabı “using namespace std;” kötü uygulama olarak kabul Neden edilir? "Hem kullanma" direktifleri hem de beyannameler yasaklanmıştır "yakınında.
Peter Mortensen

Sebep bölümünü okumadan önce, pratik olmayan sebepleri tahmin ettim çünkü şirketimde benzer kurallar var.
Gqqnbig

Yanıtlar:


69

Daha geniş soru:

Hiç böyle bir standardın uygulandığını duydunuz mu? Eğer öyleyse, arkasındaki sebep neydi?

Evet, bunu duydum ve tam nitelikli nesne adlarını kullanmak isim çarpışmalarını önler. Nadir olsalar, olduklarında, çözülmeleri çok zor olabilirler.


Bir Örnek: Bu tür bir senaryo muhtemelen bir örnekle daha iyi açıklanmaktadır.

Diyelim ki Lists<T>iki ayrı projeye ait iki tane var.

System.Collections.Generic.List<T>
MyCorp.CustomCollections.Optimized.List<T>

Tam nitelikli nesne adını kullandığımızda, hangisinin List<T>kullanılmakta olduğu açıktır . Bu açıklık açıkça ayıklamanın pahasına geliyor.

Ve "Bekle! Kimse böyle iki liste kullanmaz!" Diye tartışıyor olabilirsiniz. Bakım senaryosunu göstereceğim yer burası.

FooKurumunuz için, onaylanmış, optimize edilmiş şirketi kullanan bir modül yazdınız List<T>.

using MyCorp.CustomCollections.Optimized;

public class Foo {
    List<object> myList = ...;
}

Daha sonra, yeni bir geliştirici yaptığınız işi uzatmaya karar verir. Şirketin standartlarının farkında olmamakla birlikte, usingbloğu günceller :

using MyCorp.CustomCollections.Optimized;
using System.Collections.Generic;

Acele işlerin nasıl kötüye gittiğini görebilirsiniz.

Aynı adda iki tescilli sınıfınız olabileceğini, ancak aynı proje içinde farklı ad alanlarında olabileceğini belirtmek önemsizdir. Bu yüzden sadece .NET framework tarafından sağlanan sınıflarla çarpışmakla ilgili bir endişe değil.

MyCorp.WeightsAndLengths.Measurement();
MyCorp.TimeAndSpace.Measurement();

Gerçeklik:
Şimdi, bu büyük olasılıkla en projelerde oluşmaya? Hayır gerçek değil. Ancak, çok sayıda girdi içeren büyük bir proje üzerinde çalışırken, üzerinizde patlayan şeylerin olasılığını en aza indirmek için elinizden gelenin en iyisini yaparsınız.

Birden fazla katkıda bulunan ekipleri olan büyük projeler, uygulama dünyasında özel bir tür canavardır. Projeye giriş akışları ve katkıda bulunanların projenin kurallarını okumamış olma olasılığı nedeniyle diğer projeler için mantıksız görünen kurallar daha belirgin hale gelir.

Bu, iki büyük proje bir araya getirildiğinde de oluşabilir. Her iki projede de benzer şekilde sınıflar varsa, bir projeden diğerine referans vermeye başladığınızda çarpışmaları görürsünüz. Projeler refactor için çok büyük olabilir veya yönetim refactoring için harcanan zamanı fonlamak için masrafı onaylamaz.


Alternatifler:
Siz sormadıysanız, bunun sorun için iyi bir çözüm olmadığını göstermeye değer . Ad alanı bildirimleri olmadan çarpışacak sınıflar oluşturmak iyi bir fikir değil.

List<T>Özellikle, ayrılmış bir kelime olarak kabul edilmeli ve sınıflarınız için bir isim olarak kullanılmamalıdır.

Aynı şekilde, proje içindeki bireysel ad alanları da benzersiz sınıf adlarına sahip olmaya çalışmalıdır. Hangi ad alanıyla çalıştığınızı hatırlamak zorunda kalmak Foo(), en iyi şekilde kaçınılması gereken zihinsel bir yüktür. Sahip: başka bir yolu Dedi MyCorp.Bar.Foo()ve MyCorp.Baz.Foo()sizin geliştiriciler yukarı ve en iyi kaçınılmalıdır yolculuk için gidiyor.

Başka bir şey değilse, belirsizliği gidermek için kısmi ad alanlarını kullanabilirsiniz. Örneğin, herhangi bir Foo()sınıfı kesinlikle yeniden adlandıramazsanız , kısmi ad alanlarını kullanabilirsiniz:

Bar.Foo() 
Baz.Foo()

Mevcut projeniz için özel sebepler:

Sorunuzu, bu standardın ardından mevcut projeniz için verdiğiniz belirli nedenlerle güncellediniz. Onlara bir göz atalım ve tavşan izinden gerçekten aşağı inelim.

Tam türünü elde etmek için fareyi adın üzerine getirmeniz çok zordur. Tam nitelikli türün her zaman her zaman görünür olması daha iyidir.

"Hantal?" Um, hayır. Belki sinir bozucu. Bir ekran işaretçisini kaydırmak için birkaç ons plastik hareket ettirmek hantal değildir . Ama ben dalıyorum.

Bu akıl yürütme çizgisi her şeyden çok örtbas gibi görünüyor. Açıkçası, uygulamadaki sınıfların zayıf olarak adlandırıldığını ve sınıf adını çevreleyen uygun miktarda anlamsal bilgiyi toplamak için ad alanına güvenmeniz gerektiğini tahmin ediyorum.

Bu, tam nitelikli sınıf isimleri için geçerli bir gerekçe değildir, belki de kısmen nitelikli sınıf isimlerinin kullanılması için geçerli bir gerekçedir.

E-postayla gönderilen kod parçacıkları tam olarak nitelenmiş bir ada sahip değildir ve bu nedenle anlaşılması zor olabilir.

Bu (devam?) Akıl yürütme çizgisi, sınıfların şu anda yetersiz adlandırıldığına dair şüphelerimi pekiştiriyor. Yine, zayıf sınıf adlarına sahip olmak, her şeyin tam nitelikli bir sınıf adı kullanmasını istemek için iyi bir gerekçe değildir . Sınıf adının anlaşılması zorsa, tam sınıf adlarının düzeltebileceğinden çok daha fazla yanlış var.

Kodu Visual Studio'nun dışında (örneğin Notepad ++) görüntülerken veya düzenlerken, tam tür adını almak mümkün değildir.

Tüm nedenlerden dolayı, bu neredeyse içkimi tükürmeme neden oldu. Fakat yine de dalıyorum.

Ben sol merak ediyorum neden ekip sık düzenlerken veya Visual Studio dışında kod görüntülüyor? Ve şimdi, ad alanlarının sağlaması gerekenlere oldukça dik bir gerekçeye bakıyoruz. Bu bir takım destekli argümandır, oysa ad alanları koda örgütsel yapı sağlamak için vardır.

Takımın kendileri için ne sağlayabileceğinden faydalanmayan geliştiricilerin yanı sıra, kendi adınıza kötü adlandırma kurallarından muzdarip olan proje gibi geliyor. Ve bu gerçek sorunları çözmek yerine, belirtilerden birinin üzerine yara bandı eklemeyi denediler ve tam nitelikli sınıf isimleri istiyorlar. Bunu yanlış yönlendirilmiş bir yaklaşım olarak sınıflandırmanın güvenli olduğunu düşünüyorum.

Kötü adlandırılmış sınıflar olduğu ve yeniden canlandırıcı olamayacağı varsayılırsa, doğru cevap Visual Studio IDE'yi tam olarak kullanabilmektir. Muhtemelen VS PowerTools paketi gibi bir eklenti eklemeyi düşünün. Daha sonra, bakarken AtrociouslyNamedClass()sınıf adına tıklayabilirim, F12 tuşuna basın ve ne yapmaya çalıştığını daha iyi anlamak için doğrudan sınıf tanımına alın. Aynı şekilde, kodda şu anda kullanmak zorunda kalan tüm noktaları bulmak için Shift-F12 tuşunu tıklayabilirim AtrociouslyNamedClass().

Dış takım endişeleriyle ilgili olarak - yapılacak en iyi şey onu durdurmaktır. Parçacıklar neye atıfta bulunacaklarını hemen belirlemezlerse ileri ve geri e-postayla göndermeyin. Visual Studio'nun dışındaki diğer araçları kullanmayın, çünkü bu araçlar ekibinizin ihtiyaç duyduğu kodu çevreleyen istihbarat içermez. Notepad ++ harika bir araçtır, ancak bu görev için uygun değildir.

Bu yüzden size sunulan üç özel gerekçeyle ilgili değerlendirmenize katılıyorum. Söylendiğini düşündüğüm şey, “Bu projede ele almayan / başaramayacağımız sorunların altındayız ve bu onları 'nasıl düzelttiğimizdir' dedi. Ve bu açıkça, takım içinde sizin için kırmızı bayraklar olarak hizmet edebilecek daha derin konulara değiniyor.


1
+1. Ayrıca iç ad alanlarımızda bazı kötü çarpışmalarla karşılaştım. Her ikisi de eski kodun bir "2.0" projesine taşınmasında ve sadece farklı ad alanı bağlamlarında anlamsal olarak geçerli olan birkaç seçkin sınıf ismiyle. Gerçekten aldatıcı olan, aynı adı taşıyan iki şeyin genellikle benzer arayüzlere sahip olacağı, bu nedenle derleyiciden şikayetçi olmayacaksınız ... çalışma zamanınız!
svidgen

23
Bu sorun, açık ad alanı kullanımıyla darmadağın kod gerektiren aptal kurallar getirerek değil, ad alanı takma adları kullanılarak çözülür.
David Arno

4
@DavidArno - Sana katılmıyorum. Ancak, büyük projeler bu seçeneğe sahip olmayabilir. Ben sadece işaret ediyorum neden büyük bir proje o kuralı uygulayabilir. Ben değilim savunan değil de, Kural için. Sadece bazen gerekli çünkü takımın başka seçeneği yok.

4
@ GlenH7, cevabınızdaki diğer mevcut çözümleri belirtmek isteyebilirsiniz. İnsanların bununla karıştıklarını ve "Ah. Bu harika bir fikir!" Diye düşünmekten nefret ediyorum. Kalıcı hedef ve pragmatik olsa da +1.
RubberDuck,

3
@JimMischel - Kural bir şey için koltuk değneği olarak kullanılıyormuş gibi geliyor . O şeyin ne olduğunu belirlemek mümkün olmayabilir. Yüksek düzeyde, evet, izin usingsvermemek için bazen haklı olabilir, ancak projenizin bu vakalardan biri olarak nitelendirdiği gibi görünmemektedir.

16

Aynı adla, ancak farklı sınıf kütüphanelerinde birçok sınıfın olduğu bir şirkette çalıştım.

Örneğin,

  • Domain.Customer
  • Legacy.Customer
  • ServiceX.Customer
  • ViewModel.Customer
  • Database.Customer

Kötü tasarım diyebilirsiniz, ancak bu şeylerin organik olarak nasıl geliştiğini ve alternatifin ne olduğunu biliyorsunuz - tüm sınıfları ad alanını içerecek şekilde yeniden adlandırdınız mı? Her şeyin büyük refactoring?

Her durumda, sınıfın çoklu versiyonlarını kullanmak için tüm bu farklı kütüphaneleri referans alan projelere ihtiyaç duyulan birkaç yer vardı.

İle usingdoğrudan üstünde, bu, kıçından büyük bir acı oldu ReSharper garip şeyler yeniden yazma, denemek ve o iş yapmak yapacağını usinganında direktiflerini, Müşteri-duy-be-dökme AS-alacağı Müşteri tarzı hatalar ve hangisinin doğru olduğunu bilmiyoruz.

Yani, en azından kısmi isim alanına sahip,

var cust = new Domain.Customer

veya

public void Purchase(ViewModel.Customer customer)

Kodun okunabilirliğini büyük ölçüde geliştirdi ve istediğiniz nesneyi açıkça belirtmesini sağladı.

Kodlama standardı değildi, tam ad alanı değildi ve tüm sınıflara standart olarak uygulanmadı.


13
"alternatif nedir, ad sınıflarını içerecek şekilde tüm sınıfları yeniden adlandırın mı? Her şeyin yeniden düzenlenmesi?" Evet, bu (doğru) alternatif.
David Arno

2
Sadece kısa vadede. Kodda açık ad alanları uzun vadede kullanmaktan çok daha ucuz.
David Arno

3
Bu argümanı kabul etmekten mutlu oldum, sen bana nakit olarak ödeme yaptığın sürece hisse değil.
Ewan,

8
@David: Hayır, doğru alternatif değil. Tüm tanımlayıcıları veya en azından gerçekten çarpışanları tam olarak nitelemek doğru yoldur ve ad alanlarının ilk sırada yer almasının nedeni, aynı ad farklı modüllerde kullanıldığında çarpışmalar sağlamaktır. Mesele şu ki, bazı modüller değiştirilemeyecek kod tabanındaki 3. şahıslardan olabilir. Peki, iki farklı 3. parti kütüphaneciden gelen tanımlayıcılar çarpıştığında ve her iki kütüphaneyi de kullanmanız gerektiğine rağmen ikisini de yeniden değerlendiremezseniz ne yaparsınız? İsim alanları mevcuttur, çünkü yeniden yapılandırma her zaman mümkün değildir.
Kaiserludi

4
@CarlSixsmith, eğer Martin Fowler'in refactoring hakkındaki görüşlerine abone olursa, o zaman değişiklik kullanıcıyı etkilerse, o zaman haklısınız, yeniden yapılanma değildir; bu başka bir yeniden yapılandırma şeklidir. Bu iki nokta olsa da: 1. Tüm genel yöntemler otomatik olarak API'nin bir parçası mı? 2. Fowler , bu tanım üzerinde kaybedilen bir savaşa girdiğini, kamuoyunda yapılan değişiklikler de dahil olmak üzere genel yeniden yapılanma anlamına gelen "yeniden yapılanma" terimini kullanan ve giderek artan sayıda insanın olduğunu kabul ediyor.
David Arno

7

Çok ayrıntılı veya çok kısa olmanın faydası yoktur: çok fazla kod yazmaktan kaçınırken, ince böcekleri önlemek için yeterince ayrıntılı olan altın bir orta bulmalısınız.

C # 'da bunun bir örneği argümanların isimleridir. Birkaç kez bir çözüm aramak için harcadığım bir sorunla karşılaştım , daha ayrıntılı bir yazı stili ise ilk başta hatayı önleyebilirdi. Sorun, argümanlar sırasındaki bir hatadan ibarettir. Örneğin, size doğru görünüyor mu?

if (...) throw new ArgumentNullException("name", "The name should be specified.");
if (...) throw new ArgumentException("name", "The name contains forbidden characters.");

İlk bakışta, tamamen iyi görünüyor, ama bir hata var. İstisnaların yapıcılarının imzaları:

public ArgumentException(string message, string paramName)
public ArgumentNullException(string paramName, string message)

Argümanların sırasını fark ettiniz mi?

Yöntem, aynı türden iki veya daha fazla argüman kabul ettiğinde , bir argümanın adının belirtildiği daha ayrıntılı bir stil benimseyerek , hatanın tekrar oluşmasını önleriz.

if (...) throw new ArgumentNullException(paramName: "name", message: "The name should be specified.");
if (...) throw new ArgumentException(paramName: "name", message: "The name contains forbidden characters.");

açıkça yazmak daha uzun, ancak daha az zaman harcanan hata ayıklama ile sonuçlanır.

Aşırı noktalara itilen kişi, parametrelerin sırasını karıştırmanın bir yolu olmadığı gibi yöntemler de dahil olmak üzere her yerde adlandırılmış argümanları kullanmaya zorlayabilir doSomething(int, string). Bu, muhtemelen projeye uzun vadede zarar verecek ve yukarıda açıkladığım hatayı önlemenin faydası olmadan çok daha fazla kodla sonuçlanacaktır.

Sizin durumunuzda, “Hayır using” kuralının ardındaki motivasyon , MyCompany.Something.List<T>vs. gibi yanlış türlerin kullanılmasını zorlaştırması gerektiğidir System.Collections.Generic.List<T>.

Şahsen, böyle bir kuraldan kaçınırdım, çünkü IMHO, kod okumayı zorlaştırmanın maliyeti, yanlış türü yanlış kullanma riskinin biraz azaltılmasının yararının çok üzerindedir, ancak en azından bu kural için geçerli bir neden vardır.


Bunun gibi durumlar araçlarla tespit edilebilir. ReSharper paramName, InvokerParameterNameniteliği ile işaretler ve böyle bir parametre yoksa uyarı verir.
Johnbot,

2
@ Jobot: kesinlikle yapabilirler, ancak çok sınırlı sayıda durumda. Ya ben varsa SomeBusiness.Something.DoStuff(string name, string description)? Hiçbir araç, adın ve tanımın ne olduğunu anlayacak kadar akıllı değildir.
Arseni Mourzenko

@ArseniMourzenko bu durumda bile insanın, doğru olup olmadığını öğrenmek için zaman ayırması gerekir.
Gqqnbig

6

Ad alanları, daha kısa adlara izin veren kodlara hiyerarşik bir yapı kazandırır.

   MyCompany.Headquarters.Team.Leader
   MyCompany.Warehouse.Team.Leader

"Using" anahtar kelimesine izin verirseniz, bir olaylar zinciri var ...

  • Herkes gerçekten bir küresel ad alanı kullanıyor
    (çünkü isteyebilecekleri her ad alanını içerdikleri için)
  • İnsanlar isim çatışmaları almaya başlar veya
  • isim çatışmalarından endişe duyuyorum.

Riskten kaçınmak için herkes çok uzun isimler kullanmaya başlar:

   HeadquartersTeamLeader
   WarehouseTeamLeader

Durum yükseliyor ...

  • Başka biri zaten bir isim seçmiş olabilir, bu yüzden daha uzun bir tane kullanırsınız.
  • İsimler uzadıkça uzar.
  • Uzunlukları maksimum olmadan 60 karakteri geçebilir - saçma olur.

Bunun olduğunu gördüm, bu yüzden "kullanımı" yasaklayan şirketlere sempati duyabiliriz.


11
Yasaklama using, nükleer seçenektir. Ad alanı takma adları ve kısmi yeterlilik tercih edilir.
Jim Mischel

1

Sorun, usingaçıkça bir bildirimde bulunmaksızın ad alanına sihirli bir şekilde ekleme yapmasıdır. Bu, List<>etki alanına aşina olmadan ve onun gibi bir şeyle karşılaşan bakım programcısı için çok daha fazla bir sorundur , hangi usingmaddenin onu getirdiğini bilmiyor.

Bir yazar, eğer benzer bir sorun Java oluşur import Java.util.*;yerine import Java.util.List;örneğin; İkinci bildirge, hangi adın girildiğini belgelemektedir, böylece List<>kaynakta daha sonra gerçekleştiğinde, kökeni importbildirgeden bilinir .


6
Etki alanına aşina olmayan birinin biraz zorluk çekeceği doğru olsa da, tek yapması gereken fareyi tip isminin üzerine getirmek ve tam adını alacak. Veya sağ tıklayıp doğrudan tür tanımına gidebilir. .NET Framework türleri için muhtemelen işlerin yerini biliyordur. Etki alanına özgü türler için, rahat olması belki de bir hafta sürer. Bu noktada, tam olarak nitelenmiş isimler sadece anlayışı engelleyen gürültüdür.
Jim Mischel

Jim .. Sadece faremi bir tanımın üzerine getirmeye çalıştım ve işe yaramadı. Dünyadaki bazı programcıların Microsoft IDE'leri kullanmama ihtimalini düşündünüz mü? Her durumda, karşı olan kaynak olduğunu, benim açımdan geçersiz kılmaz kullanarak artık kendi kendini belgeleyen olduğunu
Michael Montenero

2
Evet, C # 'da çalışan insanlar var olan en iyi araçları kullanmayarak kendilerini engelliyorlar. Ve, tam yeterliliğin "kendini belgeleme" olduğu argümanının bazı yararları varken, bu tür kodların okunabilirlikte büyük bir maliyeti vardır. Tüm bu yabancı kod, kodun gerçekten önemli olan kısımlarını gizleyen gürültü yaratır.
Jim Mischel,
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.