Gerekli olmasa bile isteğe bağlı parametre isimleri belirtilsin mi?


25

Aşağıdaki yöntemi göz önünde bulundurun:

public List<Guid> ReturnEmployeeIds(bool includeManagement = false)
{

}

Ve aşağıdaki çağrı:

var ids = ReturnEmployeeIds(true);

Sistemde yeni bir geliştirici için, ne trueyaptığını tahmin etmek oldukça zor olurdu . Yapacağınız ilk şey, yöntem adının üzerine gelin ya da tanımına gidin (ikisi de en ufak iş değil). Ancak, okunabilirlik adına, şunu yazmanız mantıklı geliyor:

var ids = ReturnEmployeeIds(includeManagement: true);

Resmi olarak derleyicinin size ihtiyacı olmadığında isteğe bağlı parametreleri açıkça belirtip belirtmeyeceğini tartışan herhangi bir yer var mı?

Aşağıdaki makalede bazı kodlama kuralları anlatılmaktadır: https://msdn.microsoft.com/en-gb/library/ff926074.aspx

Yukarıdaki yazıya benzer bir şey harika olurdu.


2
Bunlar birbiriyle ilgisiz iki soru: (1) Netlik için isteğe bağlı argümanlar yazmalı mıyım? (2) Bir booleanyöntem argümanları kullanmalı mı ve nasıl?
Kilian Foth

5
Bunların hepsi kişisel tercih / stil / görüşe dayanıyor. Şahsen, iletilen değer değişmez olduğunda parametre adlarını seviyorum (bir değişken zaten adıyla yeterince bilgi iletebilir). Ama bu benim kişisel görüşüm.
MetaFight

1
belki bu bağlantıyı sorunuza örnek bir kaynak olarak dahil edebilir misiniz?
MetaFight

4
Herhangi bir şey eklerse, StyleCop ve ReSharper ile çalıştırdım - hiçbiri net göremedi. ReSharper basitçe adında parametre diyor olabilir kaldırıldı ve daha sonra bir adlandırılmış parametre söylemeye devam ediyor olması olabilir eklenebilir. Tavsiye sanırım bir nedenle ücretsiz ...: - /
Robbie Dee

Yanıtlar:


28

C # dünyasında, enumun en iyi seçeneklerden biri olacağını söyleyebilirim.

Bununla ne yaptığınızı açıklamaya zorlanacaksınız ve herhangi bir kullanıcı ne olduğunu görecekti. Gelecekteki uzantıları için de güvenlidir;

public enum WhatToInclude
{
    IncludeAll,
    ExcludeManagement
}

var ids = ReturnEmployeeIds(WhatToInclude.ExcludeManagement);

Yani, bence burada:

enum> isteğe bağlı enum> isteğe bağlı bool

Düzenleme: [Flags]Bu özel durumda uygun olabilecek bir enum hakkında LeopardSkinPillBoxHat ile ilgili aşağıdaki tartışmadan dolayı (özellikle şeyleri dahil etme / dışlama hakkında konuştuğumuz için), bunun yerine ISet<WhatToInclude>parametre olarak kullanmayı öneririm .

Çoğunlukla LINQ koleksiyon ailesine uyduğundan, ancak aynı zamanda [Flags]maksimum 32 gruba sahip olmasından kaynaklanan, birçok avantajı olan daha "modern" bir kavramdır . Kullanmanın ana dezavantajı, ISet<WhatToInclude>C # sözdiziminde kümelerin ne kadar kötü desteklendiğidir:

var ids = ReturnEmployeeIds(
    new HashSet<WhatToInclude>(new []{ 
        WhatToInclude.Cleaners, 
        WhatToInclude.Managers});

Bazıları hem set oluşturmak hem de aşağıdaki gibi "kısayol setleri" oluşturmak için yardımcı fonksiyonlarla hafifletilebilir.

var ids = ReturnEmployeeIds(WhatToIncludeHelper.IncludeAll)

Katılmaya eğilimliyim; ve gelecekte koşulların genişletilmesi konusunda belli belirsiz bir ihtimal varsa, yeni kodumda enumsları kullanmaya başlamıştım. Bir şey üçlü hale geldiğinde bir boolü bir enum ile değiştirmek gerçekten gürültülü farklar yaratır ve suçlama kodunu çok daha sıkıcı hale getirir; 3. yılda üçüncü bir seçenek için kodunuzu bir yıl sonra tekrar kullanmak zorunda kaldığınızda.
Dan Neely

3
Bu enumyaklaşımı sevdim , ama büyük bir karışım hayranı değilim Includeve Excludeaynı enumzamanda neler olup bittiğini kavramak daha zor. Bunun gerçekten genişletilebilir olmasını istiyorsanız, onu bir [Flags] enumhale getirebilir, hepsini yapabilir IncludeXxxve IncludeAllhangisinin ayarlanacağını sağlayabilirsiniz Int32.MaxValue. Daha sonra 2 ReturnEmployeeIdsaşırı yük sağlayabilirsiniz - biri tüm çalışanlara döner , diğeri WhatToIncludeenum bayraklarının kombinasyonu olabilecek bir filtre parametresi alır .
LeopardSkinPillBoxHat

@ LeopardSkinPillBoxHat Tamam, dışlama / include üzerinde katılıyorum. Yani bu biraz tartışmalı bir örnek, ancak buna IncludeAllButManagement diyebilirdim. Diğer noktasında, aynı fikirdeyim - bence [Flags]bir emanet ve sadece eski mi yoksa performans nedenlerinden dolayı mı kullanılması gerektiğini düşünüyorum. ISet<WhatToInclude>A'nın çok daha iyi bir konsept olduğunu düşünüyorum (maalesef C # kullanımı hoş hale getirmek için bazı sözdizimsel şekerlerden yoksun).
NiklasJ

@NiklasJ - Bu Flagsyaklaşımı seviyorum çünkü arayanın geçmesine WhatToInclude.Managers | WhatToInclude.Cleanersve bit yönünde çalışmasına izin veriyor veya arayanın onu nasıl işleyeceğini tam olarak ifade ediyor (örn. Yöneticiler veya temizleyiciler). Sezgisel sözdizimsel şeker :-)
LeopardSkinPillBoxHat

@ LeopardSkinPillBoxHat Kesinlikle, ama bu yöntemin tek tarafı bu. Dezavantajları örneğin sınırlı sayıda seçenek içerir ve diğer linq benzeri konseptlerle uyumlu değildir.
NiklasJ

20

yazmak mantıklı geliyor mu?

 var ids=ReturnEmployeeIds(includeManagement: true);

Bu "iyi stil" ise tartışılabilir, ancak IMHO, kod satırı "çok uzun" olmadıkça, en az kötü olmayan bir stildir ve kullanışlıdır. Adlandırılmış parametreler olmadan, açıklayıcı bir değişkeni tanıtmak da yaygın bir stildir:

 bool includeManagement=true;
 var ids=ReturnEmployeeIds(includeManagement);

Bu stil muhtemelen C # programcıları arasında adlandırılmış parametre sürümünden daha yaygındır, çünkü adlandırılmış parametreler Sürüm 4.0'dan önce dilin bir parçası değildir. Okunabilirlik üzerindeki etkisi hemen hemen aynıdır, sadece ek bir kod satırı gerektirmektedir.

Öyleyse benim tavsiyem: farklı isimlerle bir enum veya iki işlev kullanmak "overkill", ya da imzayı farklı bir nedenden dolayı değiştirmek istemiyorsanız, devam edin ve adlandırılmış parametreyi kullanın.


İkinci örnekte ek bellek kullandığınızı da belirtmek isterim
Alvaro

10
@Alvaro Bu kadar önemsiz bir durumda (değişkenin sabit bir değere sahip olduğu) doğru olması pek olası değildir. Öyle olsa bile, söylemeye değmez. Bugünlerde çoğumuz 4KB RAM ile çalışmıyoruz.
Chris Hayes,

3
Bu C # olduğundan, includeManagementyerel olarak işaretleyebilir constve herhangi bir ek bellek kullanmaktan kaçınabilirsiniz.
Jacob Krall

8
Beyler, cevabımı, sadece burada önemli olduğunu düşündüğümden rahatsız edecek herhangi bir şey eklemeyecağım.
Doktor Brown

17

Eğer gibi bir kodla karşılaşırsanız:

public List<Guid> ReturnEmployeeIds(bool includeManagement = false)
{

}

İçinde ne {}olacağını bir şey garanti hemen hemen :

public List<Guid> ReturnEmployeeIds(bool includeManagement = false)
{
    if (includeManagement)
        return something
    else
        return something else
}

Başka bir deyişle, boole iki eylem şekli arasında seçim yapmak için kullanılır: yöntemin iki sorumluluğu vardır. Bu hemen hemen bir kod kokusu garantilidir . Yöntemlerin yalnızca bir şey yapmasını sağlamak için her zaman çaba sarf etmeliyiz; sadece bir sorumluluğu var. Bu nedenle, her iki çözümünüzün de yanlış bir yaklaşım olduğunu iddia ediyorum. İsteğe bağlı parametreleri kullanmak, yöntemin birden fazla şey yaptığını gösterir. Boolean parametreleri de bunun bir işaretidir. İkisinin de olması kesinlikle alarm zillerini çalmalıdır. Bu nedenle yapmanız gereken, iki ayrı işlevsellik grubunu iki ayrı yönteme dönüştürmek. Ne yaptıklarını netleştiren yöntem adlarını verin, örneğin:

public List<Guid> GetNonManagementEmployeeIds()
{

}

public List<Guid> GetAllEmployeeIds()
{

}

Bu, hem kodun okunabilirliğini artırır hem de SOLID ilkelerini izleyerek daha iyi olmanızı sağlar.

EDIT Yorumlarda da belirtildiği gibi, bu iki yöntemin muhtemelen paylaşılan işlevselliğe sahip olacağı ve paylaşılan işlevselliğin büyük olasılıkla ne yaptığını kontrol etmek için bir boole parametresine ihtiyaç duyacak özel bir işleve dahil edileceği durumu .

Bu durumda, derleyiciye ihtiyaç duymasa da parametre adı girilmeli mi? Buna basit bir cevap olmadığını ve bu duruma göre vakaya göre karar verilmesi gerektiğini öneririm:

  • Adı belirleme argümanı, diğer geliştiricilerin (altı ay içinde kendiniz de dahil olmak üzere) kodunuzun birincil izleyicisi olması gerektiğidir. Derleyici kesinlikle ikincil bir izleyici kitlesidir. Bu nedenle, diğer insanların okumasını kolaylaştırmak için daima kod yazın; sadece derleyicinin ihtiyaç duyduğu şeyi sağlamak yerine. Bu kuralı her gün nasıl kullandığımıza bir örnek, kodumuzu _1, _2 etc değişkenleriyle doldurmadığımız, anlamlı isimler (derleyici için hiçbir şey ifade etmeyen) kullandığımızdır.
  • Karşıt argüman özel yöntemlerin uygulama detayları olduğu yönündedir. Biri, aşağıdaki gibi bir yönteme bakan birinin, boolean parametresinin amacını anlamak için, kodun içindekilerinde olduğu gibi, kodu izlemesini bekleyebilir:
public List<Guid> GetNonManagementEmployeeIds()
{
    return ReturnEmployeeIds(true);
}

Kaynak dosya ve yöntemler küçük ve kolay anlaşılır mı? Eğer evet ise, o zaman adlandırılmış parametre muhtemelen parazit anlamına gelir. Hayır ise, çok yardımcı olabilir. Yani kuralı şartlara göre uygulayın.


12
Ne dediğini duyuyorum, ama ne sorduğumun noktasını kaçırdın. O sayede bir senaryo varsayarsak olduğu , isteğe bağlı parametreleri (bu senaryolar mevcut olamayacağı) kullanmak için en uygun o gereksiz olsa bile parametreleri isim yolunda mı?
JᴀʏMᴇᴇ

4
Hepsi doğru, ancak soru böyle bir yönteme yapılan bir çağrı ile ilgiliydi . Ayrıca flag parametresi, yöntem içindeki bir dalı hiç garanti etmez. Basitçe başka bir katmana geçirilebilir.
Robbie Dee

Bu yanlış değil, basitleştirici. Gerçek kodda, public List<Guid> ReturnEmployeeIds(bool includeManagement) { calculateSomethingHereForBothBranches; if (includeManagement) return something else return something else }bu yüzden basitçe iki yönteme ayırmanın muhtemelen bu iki yöntemin parametre olarak ilk hesaplamanın sonucuna ihtiyaç duyacağı anlamına geleceğini göreceksiniz.
Doc Brown

4
Bence hepimizin söylediği şey, sınıfınızın kamusal yüzünün muhtemelen iki yöntemi (her biri bir sorumluluğu var) göstermesi gerektiğidir, ancak dahili olarak, bu yöntemlerin her biri, talebi dallanma bool parametresiyle tek bir özel yönteme makul bir şekilde iletebilir .
MetaFight

1
İki işlev arasında değişen davranış için 3 durum düşünebiliyorum. 1. Farklı olan ön işleme vardır. Genel fonksiyonların argümanları özel fonksiyona önceden işlemesini sağlayın. 2. Farklı olan son işlem var. Genel fonksiyonların sonucu özel fonksiyondan işleme almasını sağlayın. 3. Farklılık gösteren ara davranış var. Bu, dilinizin desteklediğini farz ederek, özel işleve bir lambda olarak geçirilebilir. Çoğu zaman, bu sizin için daha önce gerçekleşmediği yeniden kullanılabilir yeni bir soyutlamaya yol açar.
jpmc26

1

Sistemde yeni bir geliştirici için, doğru olanı tahmin etmek oldukça zor olurdu. Yapacağınız ilk şey, yöntem adının üzerine gelin veya tanımına gidin (ikisi de en ufak boyutta büyük işler değildir)

Evet doğru. Kendini belgeleyen kod güzel bir şeydir. Diğer cevapların da belirttiği gibi, aramanın belirsizliğini ReturnEmployeeIdsbir enum, farklı yöntem adları, vb. onları her yerde (görsel temelin ayrıntılarından hoşlanmadığın sürece).

Örneğin, bir aramayı netleştirmeye yardımcı olabilir, ancak bir başkasını değil.

Adlandırılmış bir argüman burada yardımcı olabilir:

var ids = ReturnEmployeeIds(includeManagement: true);

Fazladan netlik eklemeyin (bunun bir enum ayrıştırdığını tahmin edeceğim):

Enum.Parse(typeof(StringComparison), "Ordinal", ignoreCase: true);

Aslında netliği azaltabilir (bir kişi listedeki kapasitenin ne olduğunu anlamıyorsa):

var employeeIds = new List<int>(capacity: 24);

Ya da önemli değil çünkü iyi değişken isimleri kullanıyorsunuz:

bool includeManagement = true;
var ids = ReturnEmployeeIds(includeManagement);

Resmi olarak derleyicinin size ihtiyacı olmadığında isteğe bağlı parametreleri açıkça belirtip belirtmeyeceğini tartışan herhangi bir yer var mı?

AFAIK değil. Her iki parçayı da ele alalım: açık bir şekilde adlandırılmış parametreleri kullanmanız gereken tek zaman derleyicinin bunu yapmasını gerektirmesidir (genellikle ifade belirsizliğini kaldırmaktır). Bundan başka, istediğiniz zaman onları kullanabilirsiniz. MS'in bu makalesinde ne zaman kullanmak isteyebileceğinize dair bazı öneriler var, ancak özellikle kesin değil https://msdn.microsoft.com/en-us/library/dd264739.aspx .

Şahsen, özel nitelikler oluştururken ya da parametrelerimin değişebileceği ya da yeniden sıralanabileceği yeni bir metot hazırladığımda bunları en sık kullandığımı biliyorum (b / c isimli özellikler herhangi bir sırayla listelenebilir). Ek olarak bunları sadece satır içi statik bir değer sağlarken kullanıyorum, aksi halde değişken geçiriyorsam iyi değişken isimleri kullanmaya çalışıyorum.

TL; DR

Nihayetinde kişisel tercihe bağlı. Tabii ki, adlandırılmış parametreleri kullanmak zorunda kaldığınızda birkaç kullanım durumu vardır, ancak bundan sonra bir değerlendirme çağrısı yapmanız gerekir. IMO - Kodunuzu belgelendirmenize, belirsizliği azaltmanıza veya yöntem imzalarını korumanıza izin vereceğine inandığınız her yerde kullanın.


0

Parametre yöntemi (tam) adından açıktır ve 's varlığı yöntemi yapmak için ne gerekiyor doğal ise, gerektiği değil adlandırılmış parametre sözdizimini kullanın. Örneğin , çalışan kimliği olduğu ReturnEmployeeName(57)çok açık 57, bu yüzden adlandırılmış parametre sözdizimi ile ek açıklama gereksiz.

İle ReturnEmployeeIds(true)Dediğin gibi işlevin beyanı / belgelerine bakmak sürece, ne şekil imkansız truearaçlar - Eğer öyle olmalıdır adlandırılmış parametre sözdizimini kullanın.

Şimdi bu üçüncü durumu göz önünde bulundurun:

void PrintEmployeeNames(bool includeManagement) {
    foreach (id; ReturnEmployeeIds(includeManagement)) {
        Console.WriteLine(ReturnEmployeeName(id));
    }
}

Adlandırılmış parametre sözdizimi burada kullanılmaz, ancak bir değişkeni ilettiğimizden ReturnEmployeeIdsve bu değişkenin bir adı vardır ve bu ad, geçtiğimiz parametre ile aynı şeyi ifade eder (bu genellikle durumdur - ama her zaman değil!) - Kodun anlamını anlamak için adlandırılmış parametre sözdizimine ihtiyacımız yok.

Bu nedenle, kural basittir - sadece yöntem çağrısından parametrenin ne anlama geldiğini kolayca anlayabiliyorsanız , adlandırılmış parametreyi kullanmayın. Yapamıyorsanız - bu kodun okunabilirliğinde bir eksikliktir ve muhtemelen bunları düzeltmek istersiniz (elbette herhangi bir fiyata değil, ancak genellikle kodun okunabilir olmasını istersiniz). Düzeltmenin parametreler olarak adlandırılması gerekmez - değeri bir değişkene önce koyabilir veya diğer cevaplarda önerilen yöntemleri kullanabilirsiniz - sonuç, parametrenin ne yaptığını anlamayı kolaylaştırdığı sürece.


7
Bu kimliği ReturnEmployeeName(57)olduğunu açıkça belli kılan kabul etmiyorum 57. GetEmployeeById(57)diğer taraftan ...
Hugo Zink

@HugoZink Başlangıçta böyle bir şey kullanmak istedim, ancak bunu kasıtlı olarak değiştirdim, bunun yerine ReturnEmployeeNameyöntemin adındaki parametreyi açıkça belirtmeden bile, insanların ne olduğunu anlamalarını beklemenin oldukça makul olduğu durumları göstermek için kasıtlı olarak değiştirdim . Her halükarda, aksine ReturnEmployeeName, ReturnEmployeeIdsparametrelerin arkasındaki anlamı belirten bir şeyi makul şekilde yeniden adlandıramazsınız .
Idan Arye

1
Her durumda, ReturnEmployeeName (57) 'yi gerçek bir programda yazmamız pek mümkün değil. ReturnEmployeeName (işçi kimliği) yazmamız çok daha olası. Neden bir çalışan kimliği koyalım? Programcının kimliği olmadığı sürece ve bu çalışanın maaşına bir miktar ekleme gibi bir tür dolandırıcılık oluyor. :-)
Jay

0

Evet, bence iyi bir tarz.

Bu Boole ve tamsayı sabitleri için en anlamlı olanıdır.

Bir değişkeni geçiyorsanız, değişken adı anlamı netleştirmelidir. Olmazsa, değişkene daha iyi bir ad vermelisiniz.

Bir dizgeden geçiyorsanız, anlamı genellikle açıktır. GetFooData ("Oregon") araması görürsem, bir okuyucunun parametrenin durum adı olduğunu tahmin edebileceğini düşünüyorum.

Elbette bütün dizeler açık değildir. GetFooData ("M") görürsem, o zaman işlevi bilmediğim sürece "M" nin ne anlama geldiği hakkında hiçbir fikrim yok. M = "yönetim seviyesi çalışanları" gibi bir tür kod ise, muhtemelen değişmezden daha büyük bir numaraya sahip olmalıyız ve enum isminin açık olması gerekir.

Ve sanırım bir ip yanıltıcı olabilir. Belki yukarıdaki örneğindeki "Oregon", devlete değil, bir ürüne veya müşteriye ya da her neyse ifade eder.

Ancak GetFooData (true) veya GetFooData (42) ... bu bir anlam ifade edebilir. Adlandırılmış parametreler, kendini belgeleme yapmak için harika bir yoldur. Onları tam olarak bu amaç için birkaç kez kullandım.


0

Herhangi bulunmamaktadır süper berrak ilk etapta sözdizimi bu tip kullanmak neden olarak nedenler.

Genel olarak, belirli bir mesafeden keyfi görünebilecek mantıklı argümanlara sahip olmaktan kaçının. includeManagement(büyük olasılıkla) sonucu büyük ölçüde etkiler. Ancak argüman "az kilo" taşıyor gibi görünüyor.

Bir enum kullanımı tartışıldı, sadece "daha fazla ağırlık taşır" argümanı gibi görünmekle kalmayacak, aynı zamanda yönteme ölçeklenebilirlik sağlayacak. Ancak bu, her durumda en iyi çözüm olmayabilir, çünkü ReturnEmployeeIds-metodunuz -enum ile birlikte WhatToIncludeölçeklenmelidir ( NiklasJ'in cevabına bakınız ). Bu daha sonra başınızı ağrıtabilir.

WhatToIncludeŞunu düşünün: -enum'u ölçeklendirirseniz, ancak ReturnEmployeeIds-metod'u ölçeklendirmezseniz. Daha sonra bir ArgumentOutOfRangeException(en iyi durum) atabilir veya tamamen istenmeyen ( nullveya boş List<Guid>) bir şey getirebilir . Bazı durumlarda programcının kafasını karıştırabilir, özellikle ReturnEmployeeIdsde bir sınıf kütüphanesinde iseniz , kaynak kodun hazır olmadığı yerlerde.

Birisi WhatToInclude.Traineesişe WhatToInclude.Allyararsa, stajyerlerin hepsinin bir “altkümesi” olduğunu görerek çalışacağını varsayacaktır .

Bu (elbette), nasıl ReturnEmployeeIds uygulandığına bağlıdır .


Bir boolean argümanının kabul edilebileceği durumlarda, sizin durumunuzda bunun yerine iki yönteme (veya gerekirse daha fazla) ayırmaya çalışıyorum; bir kişi ReturnAllEmployeeIds, ReturnManagementIdsve ReturnRegularEmployeeIds. Bu, tüm temelleri kapsar ve uygulayan kişiye kesinlikle açıklayıcıdır. Bu aynı zamanda yukarıda belirtilen “ölçeklendirme” sırasına da sahip olmayacaktır.

Boolean argümanı olan bir şey için sadece iki sonuç olduğundan. İki yöntem uygulamak, çok az ekstra çaba gerektirir.

Daha az kod, nadiren daha iyidir.


Bu sözlerimle, orada vardır açıkça argüman ilan okunabilirliği artırır bazı durumlarda. Örneğin düşünün. GetLatestNews(max: 10). GetLatestNews(10)olduğu hala yeterince açıklayıcı, açık beyanı maxirade yardımı temizlemek herhangi bir karışıklığı.

Ve eğer kesinlikle bir boolean argümanına sahip olmanız gerekiyorsa , bu kullanım sadece trueveya okuyarak çıkarılamaz false. Sonra şunu söyleyebilirim:

var ids = ReturnEmployeeIds(includeManagement: true);

.. kesinlikle daha iyi ve daha fazla okunabilir:

var ids = ReturnEmployeeIds(true);

İkinci örnekte, truekesinlikle bir şey ifade ediyor olabilir . Ancak bu tartışmadan kaçınmaya çalışırdım.

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.