Silinecek öğe belirtilmediğinde hizmet istisna veya geri dönmelidir


12

Ben temsil edilebilir kod parçası var:

public class ItemService {

    public void DeleteItems(IEnumerable<Item> items)
    {
        // Save us from possible NullReferenceException below.
        if(items == null)
            return;

        foreach(var item in items)
        {
            // For the purpose of this example, lets say I have to iterate over them.
            // Go to database and delete them.
        }
    }
}

Şimdi bunun doğru bir yaklaşım mı yoksa istisna mı atmam gerektiğini merak ediyorum. Ben istisna önleyebilirsiniz, çünkü dönen boş bir koleksiyon üzerinde yineleme ile aynı olacaktır, yani, önemli bir kod zaten yürütülmez, ancak diğer yandan muhtemelen kodun bir yerinde sorunları saklıyorum, çünkü neden kimse aramak istiyorsun DeleteItemsile nullparametre? Bu, kodda başka bir yerde bir sorun olduğunu gösterebilir.

Bu çoğu zaman bir şey yapmak ve bir sonuç döndürmez, çünkü genellikle hizmet yöntemlerinde bir sorun var, bu yüzden birisi geçersiz bilgi geçerse hizmetin yapacak bir şey yok, bu yüzden döner.


2
Bu sadece benim görüşüm, ama her zaman bir yöntemin istenmeyen (istisnai) bir şey yaptığında bir istisna atması gerektiğini anlamıştım. Sizin durumunuzda, birisi null / 0 öğelerini silmeye çalışırsa bir InvalidOperationException kurarım.
Falgantil


1
@gnat Sorum, özellikle nasıl kullanıldıkları ve amaçları nedeniyle hizmetler hakkında. Bu "yinelenen" sadece genel vakalardan bahseder ve ana cevap kesin yöntemimle bile çelişir.
FCin

2
Sayılanın null yerine boş olması mümkün müdür? Bunu farklı ele alır mısın?
JAD

13
@Falgantil null'un bir istisnaya layık olduğunu görebiliyorum, ancak boş bir listeye bir istisna atmanın saçma olduğunu düşünüyorum.
Kevin

Yanıtlar:


58

Bunlar iki farklı soru.

Kabul etmeli misin null? Bu null, kod tabanındaki genel politikanıza bağlıdır . Kanımca, nullaçıkça belgelenen yerler dışında her yeri yasaklamak çok iyi bir uygulamadır, ancak kod tabanınızın zaten sahip olduğu sözleşmeye bağlı kalmak daha iyi bir uygulamadır.

Boş koleksiyonu kabul etmeli misiniz? Bence: EVET, kesinlikle. Tüm arayanları boş olmayan koleksiyonlarla sınırlamak, matematiksel olarak doğru olanı yapmaktan çok daha fazla çaba sarf ediyor - sıfır kavramına meraklı bazı geliştiricileri şaşırtsa bile.


9
Her durumda, fırlatacaksanız, AhaINoticedYouPassingInNullExceptionçalışma zamanı NullReferenceExceptionsize herhangi bir kod yazmadan zaten sizin için fırlatma olanağı sağladığında fırlatmada o kadar çok yardımcı program yoktur . Bazı yardımcı programlar vardır (örn. Kod kapsamı aracınız, önceki durumda null olarak geçmek için bir birim testiniz olup olmadığını size söyleyecektir, ancak ikincisinde değil), ancak hizmetin her çağrısında istisna denenmemelidir. çünkü bu genellikle bir programcı hatasıdır.
Steve Jessop

2
... sadece kabataslak parametreler nedeniyle ortaya çıkan istisnaları hemen yakalamalısınız, eğer geçtiğiniz şeyin bazı durumlarda boş olduğunu biliyorsanız ve aradığınız işlevin aktif olarak sizin için doğrulanmasını istiyorsanız. Kilian'ın cevabında söylediği gibi, genel politikanız açıkça izin verilmediği her yerde null'ı yasaklamak olabilir. O zaman yüksek düzey felaket kurtarma kodu dışında hiçbir yerde NullReferenceExceptionveya yakalamazsınız AhaINoticedYouPassingInNullException. Ve bu istisna işleyicisi muhtemelen bir hata raporu oluşturmalıdır :-)
Steve Jessop

2
@FCin: arayüz tasarımınız kullanıcıların gerçekte servis dışında ihtiyaç duydukları ile eşleşmelidir. Yani her arayan kişi bunu denemeye / yakalamaya çalışacaksa, bu yöntem veya bunun yanında bir kolaylık yöntemi null olup olmadığını kontrol etmeli ve görmezden gelmelidir, çünkü kamu talepleriniz budur. Kilian söylediği gibi Ancak, genellikle bir programlama hatası olarak ilerleyen boş değerlere tedavi ve daha iyi çalışır değil her çağrı yerinde sürdürmeye çalışmışlardır. Bu nedenle, ya bu yöntemin çağrıldığı hizmet ise null- denetleyiciler bu durumda da yakalamak ve devam etmek için kazan plakası içeriyor mu?
Steve Jessop

2
... öyleyse, kod tabanı sürekli olarak eksik bileşenleri düşük seviyede işlemeniz ve devam etmeniz gereken beklenen bir koşul olarak ele alıyor gibi görünüyor. Makul bir şekilde, "bu operasyonun devam edebilmesi için bir hizmet ve numaralandırmanın sorumluluğu kimdir?" Diye sorabilirsiniz. Cevap "birisi" ise, fonksiyonunuz ön koşulları kontrol etmektedir ve başarısız bir ön koşulun sonucu normalde her çağrıda değil, yüksek düzeyde yakalanan bir istisna olacaktır. İşlem için gerekli olan şeyler gerçekten isteğe bağlıysa, işleviniz beklenen bir kullanım durumunu ele almaktadır .
Steve Jessop

2
Açık bir ArgumentNullExceptionşekilde atmak, iç kodun atmasına izin vermekten daha üstündür NullReferenceException- tamamen istisna mesajına bakmak, atma alanındaki yöntem gövdesinde bir mantık hatası yerine bir giriş hatası olduğu ve erken çıkışın sağlanması anlamına gelir. daha sonra beklenmedik bir boş değerden kısmen değiştirilmektense başka verileri geçerli durumda bırakma olasılığınız daha yüksektir.
Miral

9

Boş değer

@KilianFoth'un söylediği gibi, genel politikanıza sadık kalın. Eğer nullboş bir liste için "steno" olarak değerlendirmek gerekiyorsa, bu şekilde yapın.

nullDeğerler konusunda tutarlı bir politikanız yoksa aşağıdakileri öneriyorum:

null"normal" tipiyle ifade edilemeyen durumları temsil etmek için ayrılmalıdır, örneğin null"Bilmiyorum" ifadesini kullanmak için. Ve bu iyi bir seçim, çünkü bu değeri dikkatsizce kullanmaya çalışan herkes bir istisna alacak, bu doğru olanı.

nullBoş bir liste için kısayol olarak kullanmak , mükemmel bir temsil olduğu için sıfır öğeli bir liste olduğu için bu şekilde nitelendirilmez. Ve teknik olarak kötü bir seçimdir, çünkü kodunuzun listelerle ilgili her bölümünü geçerli stenoyu kontrol etmeye zorlar null.

Boş liste

Bir DeleteItems()yöntem için, boş bir listeyi etkin bir şekilde geçirmek hiçbir şey yapmamak anlamına gelir. Buna bir argüman olarak izin verdim, bir istisna atmak değil, sadece çabucak geri dönüyorum.

Tabii ki, arayan önce sıfır öğeleri kontrol DeleteItems()edebilir ve bu durumda aramayı atlayabilir . Bir web API'sinden bahsediyorsak, verimlilik nedenleriyle arayan , gereksiz trafik ve gidiş-dönüş gecikmelerinden kaçınmak için bunu yapmalıdır . Ancak API'nızın bunu zorlaması gerektiğini düşünmüyorum.


1

Bir istisna atın ve arama kodunda null değerlerini kullanın.

Bir tasarım kuralı olarak parametre değerleri olarak null değerinden kaçınmaya çalışın. NullPointerExceptions'ı genel olarak azaltacaktır, çünkü null'ler gerçekten bir istisna olacaktır.

Bunun yanı sıra, kodunuzun geri kalanına bakın. Bu, projenizde ortak bir kalıpsa tutarlı olun.


Hizmetlerimin nasıl yapılandırıldığını "şekillendirmek" in ortasındayım, bu yüzden bazı yeniden düzenleme geçersiz girişi atmak için gerekli olabilir, ama çok değil. Ama null'ları atmaya başladıktan sonra gizlemek yerine bir istisna haline geleceğinize katılıyorum.
FCin

0

Genel olarak konuşursak, istisnalar atma istisnai durumlar için ayrılmalıdır, yani kodun mevcut bağlamda gerçekleştirilecek makul bir eylem tarzı yoksa.

Bu düşünce sürecini bu duruma uygulayabilirsiniz. Bunun herkese açık bir yöntemi olan genel bir sınıf olduğu göz önüne alındığında, genel bir API'niz var ve teoride neyin geçtiği üzerinde hiçbir kontrol yok.

Kodunuzda neyi çağırdığı hakkında bir bağlam yoktur (olması gerektiği gibi) ve null değeriyle makul bir şekilde yapabileceğiniz hiçbir şey yoktur. Bu kesinlikle bir ArgumentNullException.


msgstr "kodun mevcut bağlamda gerçekleştirilecek makul bir eylem tarzı yoksa". Ama benim düşüncem, boşluğa dönüşecek makul bir eylem tarzı var. Boş koleksiyonu geçerken aynı şeyi yapar, bu yüzden boş koleksiyona izin verirsem neden izin vermeyeyim null.
FCin

1
@FCin Boş bir koleksiyon nedeniyle boş olduğunu biliyorsunuz. İle nullsize hiçbir koleksiyona sahip. Çağıran kodun yönteme bir koleksiyon sağlaması gerekiyorsa / bekleniyorsa, yanlış bir şey var, bu yüzden atmalısınız. Boş bir koleksiyonla aynı bir boş değere sahip olmanın tek nedeni, arama kodunun boş koleksiyonlar üretmesini makul bir şekilde beklemenizdir. Diğer cevapların belirttiği gibi, çoğu zaman, bir şey nullbir anomalidir. Bunları boş koleksiyonlarla aynı şekilde ele alırsanız, kodun başka bir yerinde bir sorunu yok sayıyor olabilirsiniz.
JAD

@FCin: ayrıca, nullboş demek isterseniz , bu yönteme özgüdür. Aynı kod tabanının başka bir yerinde, bir tür filtreleme yapan bir IEnumerableveya IContainerparametreniz nullolabilir , "filtre yok" (her şeye izin ver) anlamına gelirken boş bir filtre hiçbir şeye izin vermez. Ve başka bir yerde, nullaçıkça "Bilmiyorum" anlamına gelebilir. Bu nedenle, nullher yerde her zaman aynı anlama gelmediği düşünüldüğünde, bu anlam bir kişi için gerekli değilse veya en azından biri için faydalı olmadıkça, bunun için hiçbir anlam icat etmemek iyi bir fikirdir.
Steve Jessop

0

Bu soru istisnalar değil, nullgeçerli bir argüman olmakla ilgili .

Yani, her şeyden önce null, bu yöntemin argümanı için izin verilen bir değer olup olmadığına karar vermelisiniz . Öyleyse, bir istisnaya ihtiyacınız yoktur. Değilse, bir istisnaya ihtiyacınız vardır.

İzin vermek isteyip istemediğiniz null , bu konuda çok sayıda Google isabeti ile gösterildiği gibi tartışmalıdır. Yani, net bir cevap alamayacaksınız ve çalıştığınız yerde biraz fikir ve geleneklere kalmış.

Başka bir çekişme alanı, bir kütüphane işlevinin hatalı parametreleri "düzeltmeye" çalışmadığı sürece, tür şeyler hakkında gerçekten katı mümkün olduğunca yumuşak . Bunu ağ protokolleri, posta transferi vb. İle karşılaştırın (bunlar programlama yöntemlerinde olduğu gibi arayüz sözleşmeleri). Genellikle, politika, gönderenin protokole olabildiğince sıkı bir şekilde uyması gerektiğidir, ancak alıcı, gelen her şeyle çalışabilmek için kendi yolundan gitmelidir.

Yani karar vermelisiniz: nullElleçleme gibi oldukça büyük bir politika uygulamak gerçekten bir kütüphane yönteminin işi midir? Özellikle kütüphaneniz başka kişiler tarafından da kullanılıyorsa (farklı politikaları olabilir).

Muhtemelen nulldeğerlere izin verme , semantiklerini tanımlama ve belgeleme tarafında hata yapardım (yani, null = empty arraybu durumda) ve diğer benzer kodunuzun ("kütüphane" stil kodu)% 99'u bunu yapmazsa , bir istisna atmazdım 'yuvarlak.


1
"Boş işleme gibi oldukça büyük bir politika uygulamak gerçekten bir kütüphane yönteminin işi midir?" - bu düşünce çizgisinde, bir politikayı gerçekte uygulamak yerine, bir politikayı uygulamaya yardımcı olmanıza yardımcı olan, yapmak istediğiniz şey varsa, hata ayıklama modları bulunur . Dolayısıyla, kabul ettiğiniz şeylerde nullliberal olma prensibini yutacaksanız, giriş yapmak ve hatta atmak, niyeti geçtikleri konusunda katı olmak, ancak hem kodunu hem de dağınıklığı olan insanlar için yararlı olacaktır. ünitelerini nullyine de geçtikleri ölçüde test ederler .
Steve Jessop

@SteveJessop, cevabımın ruhuna karşı olup olmadığınızı ya da çizgisi boyunca devam edip etmediğinizi gerçekten bilmiyorum. Bununla birlikte, sadece yutmayı önermiyorum null, ancak kabul edilebilir (veya OP'nin hangi çözüme ulaştığına bağlı olarak bağlı değil) yöntemin sözleşmesinde açık bir şekilde beyan etmesini ve ardından bir istisna atmak isteyip istemediğini söyledim. (ya da değil) kendini çözer.
AnoE
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.