İstisnalar - girişler teknik olarak geçerli, ancak karşılanamaz olduğunda belirlenen boş sonuç


108

Kamuya açıklanması amaçlanan bir kütüphane geliştiriyorum. Nesnelerin kümeleri üzerinde çalışmak için çeşitli yöntemler içerir - kümeleri oluşturmak, incelemek, bölümlemek ve kümeleri yeni biçimlere yansıtmak. İlgili olması durumunda, IEnumerableNuGet paketi olarak piyasaya sürülecek LINQ tarzı uzantıları içeren bir C # sınıfı kütüphanedir .

Bu kütüphanedeki yöntemlerden bazıları tatmin edici olmayan giriş parametreleri verilebilir. Örneğin, birleşik yöntemlerde, bir m öğesi kaynağından oluşturulabilecek tüm n öğesi kümesini üretmek için bir yöntem vardır . Örneğin, set verildiğinde:

1, 2, 3, 4, 5

ve 2 kombinasyonunun istenmesi şunları üretecektir:

1, 2
1, 3
1, 4
vb ...
5, 3
5, 4

Şimdi, 3 maddeden oluşan bir set vermek ve ardından her bir maddeyi yalnızca bir kez kullanabileceğini belirten seçeneği belirlerken, 4 maddeden oluşan bir kombinasyon istemek gibi, yapılamayan bir şeyi istemek açıkça mümkün.

Bu senaryoda, her parametre ayrı ayrı geçerlidir:

  • Kaynak koleksiyonu boş değil ve öğe içeriyor
  • İstenen kombinasyon boyutu pozitif olmayan sıfır tamsayıdır
  • İstenen mod (her öğeyi yalnızca bir kez kullanın) geçerli bir seçimdir

Ancak, birlikte alındığında parametrelerin durumu sorunlara neden olur.

Bu senaryoda, yöntemin bir istisna (örneğin InvalidOperationException) atmasını veya boş bir koleksiyon döndürmesini bekler misiniz ? Her ikisi de benim için geçerli görünüyor:

  • Sen kombinasyonlarını üretemez n kümesinden öğeleri m öğeleri nerede n> m sadece bir defa her öğeyi kullanma izni, bu nedenle bu işlem dolayısıyla imkansız varsayılması durumunda InvalidOperationException.
  • N> m boş bir set olduğunda , m öğelerinden üretilebilecek n boyut kombinasyonları kümesi; hiçbir kombinasyon üretilemez.

Boş küme argümanı

İlk endişem, bir istisnanın, bilinmeyen büyüklükteki veri kümeleriyle çalışırken yöntemlerin deyimsel LINQ tarzı zincirlemesini önlemesidir. Başka bir deyişle, böyle bir şey yapmak isteyebilirsiniz:

var result = someInputSet
    .CombinationsOf(4, CombinationsGenerationMode.Distinct)
    .Select(combo => /* do some operation to a combination */)
    .ToList();

Girdi kümeniz değişken boyuttaysa, bu kodun davranışı öngörülemez. Eğer .CombinationsOf()bir özel durum atar someInputSet4'ten daha az öğesi vardır, o zaman bu kod olacak bazen bazı ön denetimi olmadan zamanında başarısız. Yukarıdaki örnekte bu kontrol önemsizdir, ancak daha uzun bir LINQ zincirinin yarısına kadar çağırıyorsanız, bu sıkıcı olabilir. Boş bir küme döndürürse, resulttamamen memnun olabileceğiniz boş olacaktır.

Bir istisna argümanı

İkinci kaygım, boş bir setin geri dönmesinin problemleri gizleyebileceğidir - bu yöntemi bir LINQ zincirinin yarısına kadar çağırıyorsanız ve sessizce boş bir küme döndürürseniz, daha sonra birkaç adımda sorun yaşayabilir veya kendinizle boş Sonuç kümesinde ve giriş kümesinde kesinlikle bir şey olduğu göz önüne alındığında bunun nasıl gerçekleştiği açık olmayabilir.

Ne beklersiniz ve bunun konusundaki argümanınız nedir?


66
Boş küme matematiksel olarak doğru olduğu için, şansınız olduğunda aslında istediğiniz şeydir. Matematiksel tanımlar ve sözleşmeler genel olarak tutarlılık ve kolaylık sağlamak için seçilmiştir, böylelikle işler sadece onlarla sonuçlanır.
Asmeurer

5
@ asmeurer Teoremlerin tutarlı ve kullanışlı olması için seçildiler . Programlamayı kolaylaştırmak için seçilmemiştir. (Bu bazen bir yan faydadır, ancak bazen programlamayı da zorlaştırır.)
jpmc26

7
@ jpmc26 "Bunlar teoremlerin tutarlı ve kullanışlı olması için seçildi" - programınızın her zaman beklendiği gibi çalıştığından emin olmak temelde bir teoremi ispatlamaya eşdeğerdir.
artem

2
@ jpmc26 Neden işlevsel programlamadan bahsettiğinizi anlamıyorum. Zorunlu programlar için doğruluğu kanıtlamak oldukça mümkün, her zaman avantajlıdır ve gayrı resmi olarak da yapılabilir - sadece biraz düşünün ve programınızı yazarken genel matematiksel anlam kullanın ve daha az zaman harcayacaksınız. Bir örnek üzerinde istatistiksel olarak kanıtlanmış ;-)
artem

5
@DmitryGrigoryev 1/0 tanımsız olarak sonsuzluk olarak 1/0 değerinden çok daha matematiksel olarak doğrudur.
asmeurer,

Yanıtlar:


145

Boş Bir Küme Dön

Boş bir set beklerdim çünkü:

Her sayıyı yalnızca bir kez kullanabildiğimde, 3 kümeden 4 sayı 0 kombinasyon var.


5
Matematiksel olarak, evet, ama aynı zamanda büyük olasılıkla bir hata kaynağıdır. Bu tür bir giriş bekleniyorsa, kullanıcının genel amaçlı bir kitaplıktaki istisnayı yakalamasını istemek daha iyi olabilir.
Casey Kuball

56
Bunun bir "çok muhtemel" hata sebebi olduğuna katılmıyorum. Örneğin, geniş bir girdi kümesinden saf "eşleştirme" algoritması uyguladığınızı varsayalım. İki öğenin tüm kombinasyonlarını isteyebilir, aralarındaki tek "en iyi" eşleşmeyi bulabilir ve sonra her iki öğeyi de kaldırabilir ve yeni, daha küçük setle baştan başlayabilirsiniz. Sonunda setiniz boş olacak ve dikkate alınması gereken hiçbir çift kalmayacak: bu noktada bir istisna engelleyici. Benzer bir durumda sonuçlanmanın pek çok yolu olduğunu düşünüyorum.
amalloy

11
Aslında bunun kullanıcının gözünde bir hata olup olmadığını bilmiyorsunuz. Boş küme, gerekirse kullanıcının kontrol etmesi gereken bir şeydir. if (result.Any ()) DoSomething (result.First ()); başka bir DoSomethingElse (); denemekten çok daha iyidir {result.first (). dosomething ();} catch {DoSomethingElse ();}
Guran

4
@TripeHound Sonunda kararı veren şey buydu: geliştiricinin kontrol etmek ve sonra atmak için bu yöntemi kullanmasını istemek, geliştirme çabası, program performansı ve program akışının basitliği.
anaximander

6
@Darthfett Bunu, var olan bir LINQ uzatma yöntemiyle karşılaştırmayı deneyin: Where (). Bir cümlecik varsa: Nerede (x => 1 == 2 2) İstisna alamıyorum, boş bir set alıyorum.
Necoras,

79

Şüpheniz olduğunda, başka birine sorun.

Örnek fonksiyonunuz Python: 'da çok benziyor itertools.combinations. Nasıl çalıştığını görelim:

>>> import itertools
>>> input = [1, 2, 3, 4, 5]
>>> list(itertools.combinations(input, 2))
[(1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5)]
>>> list(itertools.combinations(input, 5))
[(1, 2, 3, 4, 5)]
>>> list(itertools.combinations(input, 6))
[]

Ve bana çok iyi geliyor. Tekrarlayabileceğim bir sonuç bekliyordum ve bir tane aldım.

Ama apaçık bir şey soracak olsaydın, belli ki:

>>> list(itertools.combinations(input, -1))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: r must be non-negative

Yani, tüm parametreleriniz doğrulanırsa ancak sonuç boş bir küme, boş bir küme döndürürseniz, bunu yapan sadece siz değilsiniz.


@Bakuriu tarafından yorumlarda belirtildiği gibi, bu aynı zamanda SQLgibi bir sorgu için aynıdır SELECT <columns> FROM <table> WHERE <conditions>. Sürece <columns>, <table>, <conditions>iyi oluşturulmuş ve mevcut isimleridir şekilde yer alır, birbirinizi dışarıda bir dizi şartı inşa edebilirsiniz. Sonuçta ortaya çıkan sorgu, sadece bir atmak yerine hiçbir satır vermeyecek InvalidConditionsError.


4
Reddedildi, çünkü C # / Linq dil alanında aptalca değil (Sbecker'in sınır dışı sorunların dilde ne kadar benzer şekilde ele alındığına ilişkin cevabına bakınız). Bu bir Python sorusu olsaydı, benden bir +1 olurdu.
James Snell

32
@JamesSnell Sınırların dışında bir problemle nasıl bağlantılı olduğunu çok az görüyorum. Bunları yeniden sıralamak için dizine göre nöğeleri seçmiyoruz, onları toplama biçimimizi saymak için koleksiyondaki öğeleri seçiyoruz. Bir noktada, onları toplarken hiçbir eleman kalmazsa n, söz konusu koleksiyondan elemanların toplanmasının bir yolu yoktur (0) .
Mathias Ettinger

1
Yine de, Python C # soruları için iyi bir kehanet değildir: örneğin C # izin verir 1.0 / 0, Python bunu yapmaz.
Dmitry Grigoryev

2
@MathiasEttinger Python'un istisnaların nasıl ve ne zaman kullanılacağına ilişkin yönergeleri C # 'dan çok farklıdır, bu nedenle Python modüllerinin davranışını bir kılavuz olarak kullanmak C # için iyi bir ölçüm değildir.
Ant P,

2
Python'u seçmek yerine sadece SQL'i seçebilirdik. Bir mu iyi biçimli SELECT sonuç kümesi boş olduğunda bir tablo üzerinde sorgu istisna üretmek? (spoiler: hayır!). Bir sorgunun "iyi biçimlendirilmişliği" yalnızca sorgunun kendisine ve bazı meta verilere bağlıdır (örneğin, tablo var mı ve bu alana sahip mi (bu tür ile)?) Sorgu iyi oluşturulduktan ve bir kez beklediğinizde (muhtemelen boş) geçerli sonuç veya "istisna" sorunu olduğu için bir istisna (ör. db sunucusu çöktü veya başka birşey).
Bakuriu

72

Layman'ın terimiyle:

  • Bir hata varsa, bir istisna oluşturmalısınız. Bu, hatanın tam olarak nerede olduğunu bilmek için, zincirleme bir çağrı yerine adım adım işlerin yapılmasını içerebilir.
  • Hata yoksa ancak sonuçta ortaya çıkan set boşsa, bir istisna yükseltme yapmayın, boş grubu geri getirin. Boş bir set geçerli bir set.

23
+1, 0 tamamen geçerli ve gerçekten de çok önemli bir sayı. Bir sorgunun yasal olarak sıfır isabet getirebileceği pek çok durum vardır, bir istisna oluşturmanın çok sinir bozucu olacağı sonucuna varılmıştır.
Kilian Foth,

19
iyi bir tavsiye, ama cevabınız açık mı?
Ewan

54
Ben hala bu cevabın OP'nin throwboş bir set geri dönmesi gerektiğini ya da geri dönmesini önerdiği konusunda hiçbir bilgim yok ...
James Snell

7
Cevabınız, bir hata olup olmadığına bağlı olarak ikisini de yapabileceğimi söylüyor, ancak örnek senaryoyu bir hata olarak kabul edip etmeyeceğinizi söylemiyorsunuz. Yukarıdaki yorumda, "sorun yoksa" boş bir küme döndürmem gerektiğini söylüyorsunuz, ancak yine de, tatmin edilemeyen koşullar bir sorun olarak görülebilir ve gerektiğinde istisnaları artırmadığımı söylemeye devam edersiniz. Peki ben ne yapmalıyım?
anaximander

3
Ah, anladım - yanlış anladınız; Hiçbir şey zincirlemiyorum, zincirde kullanılmasını beklediğim bir yöntem yazıyorum. Bu yöntemi kullanan varsayımsal geleceğin geliştiricisinin yukarıdaki senaryoda atılmasını isteyip istemediğini merak ediyorum.
anaximander

53

Ewan'ın cevabına katılıyorum ama belirli bir akıl yürütme eklemek istiyorum.

Matematiksel işlemlerle uğraşıyorsunuz, bu yüzden aynı matematiksel tanımlara uymak iyi bir tavsiye olabilir. Matematiksel bir bakış açısından sayısı r bir ve -Görüntüler N -SET (yani nCr ) de tüm r için tanımlandığı gibidir> n> = 0. sıfırdır. Bu nedenle, boş bir kümenin döndürülmesi, matematiksel bir açıdan beklenen durum olacaktır.


9
Bu iyi bir nokta. Kitaplık daha yüksek bir seviyedeyse, bir palet yapmak için renk kombinasyonları seçmek gibi - o zaman bir hata atmak mantıklı olur. Çünkü renginiz olmayan bir paletin bir palet olmadığını biliyorsunuz . Ancak girişleri olmayan bir küme hala bir kümedir ve matematik onu boş bir kümeye eşit olarak tanımlar.
Kaptan Adam

1
Ewans'ın cevaplarından çok daha iyi olması matematiksel pratiği gösteriyor. +1
kullanıcı949300

24

İstisna kullanıp kullanmamayı belirlemenin iyi bir yolunu buluyorum, insanların bu işlemde yer aldığını hayal etmektir.

Bir dosyanın içeriğini örnek alarak almak:

  1. Lütfen bana dosya içeriğini getir, "değil.

    a. "İşte içeriği: boş bir karakter koleksiyonu"

    b. "Erm, bir sorun var, bu dosya yok. Ne yapacağımı bilmiyorum!"

  2. Lütfen bana dosyanın içeriğini getir, "var ancak boş.

    a. "İşte içeriği: boş bir karakter koleksiyonu"

    b. "Erm, bir sorun var, bu dosyada hiçbir şey yok. Ne yapacağımı bilmiyorum!"

Hiç şüphe yok ki, bazıları aynı fikirde olmayacak, ancak çoğu kişi için "Erm, bir sorun var", dosyanın bulunmadığı bir anlam ifade ediyor ve dosya boşken "boş bir karakter koleksiyonu" döndürüyor.

Yani aynı yaklaşımı örneğinize uygulayın:

  1. Lütfen bana 4 öğenin tüm kombinasyonlarını ver {1, 2, 3}

    a. Yok, işte boş bir küme.

    b. Bir sorun var, ne yapacağımı bilmiyorum.

Yine, örneğin bir nullöğe kümesi olarak teklif edildiyse "bir sorun var" mantıklı olur , ancak "burada boş bir küme" yukarıdaki talebe makul bir yanıt gibi görünüyor.

Boş bir değer döndürmek bir sorunu gizlerse (örneğin eksik bir dosya, a null), bunun yerine genel bir istisna kullanılmalıdır (seçtiğiniz dil option/maybetürleri desteklemediği sürece bazen daha anlamlı olur). Aksi takdirde, boş bir değerin geri verilmesi büyük olasılıkla maliyeti basitleştirir ve en az şaşkınlık ilkesine daha iyi uyar.


4
Bu tavsiye iyidir, ancak bu dava için geçerli değildir. Daha iyi bir örnek: 30: Ocak ayından sonra kaç gün ?: 1 30: Şubat ayının sonundan kaç gün sonra: 0 30: sabahtan 30 gün sonra kaç gün ?: İstisna 30’da kaç çalışma saati : şubatın th: İstisna
Guran

9

Genel amaçlı bir kütüphane için içgüdüm, son kullanıcının seçmesine izin vermek olacaktır .

Elimizdeki Parse()ve bizim için TryParse()uygun olan gibi , fonksiyondan hangi çıktıya ihtiyacımız olduğuna bağlı olarak kullanabileceğimiz bir seçeneğe sahip olabiliriz. İşlevin tek bir sürümünü seçmek yerine, istisnayı atmak için bir işlev sargısı yazıp bakımını yapmak için daha az zaman harcarsınız.


3
+1 çünkü her zaman seçim fikrinden hoşlanırım ve bu örüntü programcıları kendi girdilerini doğrulamaya teşvik etme eğilimindedir. Bir TryFoo fonksiyonunun sadece varlığı bazı girdi kombinasyonlarının sorunlara yol açabileceğini ve belgelerin bu olası sorunların ne olduğunu açıklarsa kodlayıcı onları kontrol edebilir ve geçersiz girdileri yalnızca bir istisna yakalayarak daha temiz bir şekilde ele alabilir. veya boş bir gruba cevap verme. Veya tembel olabilirler. Her iki durumda da, karar onların.
aleppke

19
Hayır, boş bir set matematiksel olarak doğru cevaptır. Başka bir şey yapmak, bir hevesle yapılmaması gereken kesin olarak üzerinde anlaşılan matematiği yeniden tanımlamaktadır. Biz varken, üs sıfıra eşitse bir hata atmak için üs üs işlevini yeniden tanımlamalı mıyız?
Wildcard

1
Benzer bir şeyi cevaplamak üzereydim. Linq uzatma yöntemleri Single()ve SingleOrDefault()hemen akla yayıldı. Sıfır veya> 1 sonuç varsa, Single bir istisna atarken, SingleOrDefault atmayacak ve yerine geri dönecektir default(T). Belki OP kullanabilir CombinationsOf()ve CombinationsOfOrThrow().
RubberDuck

1
@Wildcard - aynı giriş olmayan aynı giriş için iki farklı sonuçtan bahsediyorsunuz. OP sadece a) sonucu seçmek veya b) sonuç olmayan bir istisna oluşturmakla ilgilenmektedir .
James Snell,

4
Singleve SingleOrDefault(veya Firstve FirstOrDefault) tamamen farklı bir hikaye, @RubberDuck. Örneğimi önceki yorumumdan alıyorum. Bu Anser bile iyi bir sonuçtur hiçbiri sorguya "bile iki mevcut büyüktür asal nedir?" Çünkü bu matematiksel olarak sağlam ve mantıklı bir cevaptır. Her neyse, "İkiden büyük olan ilk bile nedir?" doğal bir cevap yok. Sadece soruya cevap veremezsin, çünkü tek bir numara istiyorsun. Hiçbiri değil (tek bir sayı değil, bir küme), 0 değil. Dolayısıyla bir istisna atarız.
Paul Kertscher

4

İşleviniz çağrıldığında verilen argümanları doğrulamanız gerekir. Ve aslına bakarsan, geçersiz argümanlarla nasıl başa çıkılacağını bilmek istiyorsun. Çoklu argümanların birbirine bağlı olması, argümanları doğruladığınız gerçeğini telafi etmemektedir.

Bu nedenle, kullanıcının neyin yanlış gittiğini anlaması için gerekli bilgileri sağlayan ArgumentException için oy kullanırdım.

Örnek olarak, public static TSource ElementAt<TSource>(this IEnumerable<TSource>, Int32)Linq içindeki işlevi kontrol edin . Dizin 0'dan küçük veya daha büyükse ya da kaynaktaki öğelerin sayısına eşitse, bu bir ArgumentOutOfRangeException değerini verir. Böylece indeks arayan tarafından sağlanan numaralandırılabilir açısından doğrulanır.


3
Dilde benzer bir durumdan bahseden +1.
James Snell

13
İşin garibi, örneğiniz beni düşündürdü ve beni güçlü bir karşı örnek yaptığını düşündüğüm bir şeye yönlendirdi. Belirttiğim gibi, bu yöntem LINQ benzeri olacak şekilde tasarlanmıştır, böylece kullanıcılar onu diğer LINQ yöntemleriyle birlikte zincirleyebilir. Eğer new[] { 1, 2, 3 }.Skip(4).ToList();boş bir set alırsanız, boş bir setin geri dönmesinin belki de daha iyi bir seçenek olduğunu düşündürür.
anaximander

14
Bu bir dil anlam sorunu değil, sorun alanının anlambilimi zaten doğru cevabı veriyor, yani boş kümeyi geri veriyor. Başka bir şey yapmak, kombinasyonel problem alanında çalışan biri için en az şaşkınlık ilkesini ihlal ediyor.
Ukko

1
Boş bir set döndürme argümanlarını anlamaya başladım. Neden mantıklı olurdu. En azından bu özel örnek için.
sbecker,

2
@sbecker, konuyu eve getirmek için: Eğer soru "Kaç tane kombinasyon var ..." olsaydı, o zaman "sıfır" tamamen geçerli bir cevap olurdu. Aynı şekilde, "Ne vardır tamamen geçerli bir cevap olarak boş kümesi vardır ... Bu kombinasyonlar böyle". Eğer soru, "Bu şekilde ilk kombinasyon nedir ..." olsaydı, o zaman ve ancak o zaman bir istisna uygun olurdu, çünkü soru cevaplanamaz. Ayrıca Paul K'nın yorumuna bakınız .
Wildcard

3

Aşağıdakilerden birini yapmalısınız (negatif sayıda kombinasyon gibi temel sorunlara sürekli olarak devam etmesine rağmen):

  1. Biri girdiler saçma olduğunda diğeri boşa atıldığında boş bir set döndüren iki uygulama sağlayın. Onları aramayı dene CombinationsOfve CombinationsOfWithInputCheck. Ya da ne istersen. Bunu tersine çevirebilirsiniz, böylece giriş kontrolü daha kısa olan isim ve bir tane daha listelenir CombinationsOfAllowInconsistentParameters.

  2. Linq yöntemleri için, boş IEnumerableolarak belirttiğiniz öncül tesiste boşa dönün . Ardından, bu Linq yöntemlerini kütüphanenize ekleyin:

    public static class EnumerableExtensions {
       public static IEnumerable<T> ThrowIfEmpty<T>(this IEnumerable<T> input) {
          return input.IfEmpty<T>(() => {
             throw new InvalidOperationException("An enumerable was unexpectedly empty");
          });
       }
    
       public static IEnumerable<T> IfEmpty<T>(
          this IEnumerable<T> input,
          Action callbackIfEmpty
       ) {
          var enumerator = input.GetEnumerator();
          if (!enumerator.MoveNext()) {
             // Safe because if this throws, we'll never run the return statement below
             callbackIfEmpty();
          }
          return EnumeratePrimedEnumerator(enumerator);
       }
    
       private static IEnumerable<T> EnumeratePrimedEnumerator<T>(
          IEnumerator<T> primedEnumerator
       ) {
          yield return primedEnumerator.Current;
          while (primedEnumerator.MoveNext()) {
             yield return primedEnumerator.Current;
          }
       }
    }
    

    Son olarak, böyle kullanın:

    var result = someInputSet
       .CombinationsOf(4, CombinationsGenerationMode.Distinct)
       .ThrowIfEmpty()
       .Select(combo => /* do some operation to a combination */)
       .ToList();
    

    veya bunun gibi:

    var result = someInputSet
       .CombinationsOf(4, CombinationsGenerationMode.Distinct)
       .IfEmpty(() => _log.Warning(
          $@"Unexpectedly received no results when creating combinations for {
             nameof(someInputSet)}"
       ))
       .Select(combo => /* do some operation to a combination */)
       .ToList();
    

    Özel yöntemin halka olanlardan farklı olmasının, atma veya aksiyon davranışının, linq zinciri oluşturulduktan bir süre sonra, numaralandırıldığı zaman gerçekleşmesi durumunda ortaya çıkması gerektiğini lütfen unutmayın. Sen istemek doğru atmak.

    Bununla birlikte, elbette, herhangi bir maddenin olup olmadığını belirlemek için en azından ilk maddeyi sayması gerektiğine dikkat edin. Bu çoğunlukla ileride izleyiciler oldukça kolay bir sonuç çıkarma gerçeğiyle hafifletilir düşünüyorum potansiyel bir dezavantajı ThrowIfEmptyyöntem vardır en az bir öğe numaralandırmak için, bu yüzden gerektiğini değil o böyle yaparak şaşırmayın. Ama sen asla bilemezsin. Bunu daha açık hale getirebilirsin ThrowIfEmptyByEnumeratingAndReEmittingFirstItem. Ama bu devasa bir overkill gibi görünüyor.

Bence # 2 oldukça iyi, harika! Şimdi, güç arama kodunda ve bir sonraki kod okuyucusu tam olarak ne yaptığını anlayacak ve beklenmeyen istisnalarla uğraşmak zorunda kalmayacak.


Lütfen ne demek istediğini açıkla. Yazımda "küme gibi davranmıyor" bir şey nasıl ve neden bu kötü bir şey?
ErikE

Temelde, sonuç uu değişmez yerine bir olursa Durum sorgulamak happend sorgu sarılması, cevabım aynı yapıyorlar
GameDeveloper

Cevabımın cevabın "temelde aynısını nasıl yaptığını" göremiyorum. Bana tamamen farklı görünüyorlar.
ErikE

Temelde "benim kötü sınıfım" ın aynı koşulunu uyguluyorsunuz. Ama bunu söylemiyorsun ^^. Sorgu sonucundaki 1 öğenin varlığını zorladığınızı kabul ediyor musunuz?
GameDeveloper

Hala neden bahsettiğini anlamayan aptal aptal programcılar için daha net konuşmalısın. Hangi sınıf kötü? Bu neden kötü? Hiçbir şey zorlamıyorum. Sınıfın KULLANICISI, sınıfın YARATICISI yerine nihai davranışa karar vermesine izin veriyorum. Bu, Linq yöntemlerinin, bir kerede -1 öğe istemeniz gibi normal kuralların ihlali olmayan bir hesaplama özelliği nedeniyle rastgele atılmadığı tutarlı bir kodlama paradigması kullanmanıza izin verir.
ErikE

2

Her iki kullanım durumunun da argümanlarını görebiliyorum - aşağı kod, veri içeren kümeleri beklediğinde istisna harika. Öte yandan, eğer beklenirse boş bir set mükemmeldir.

Bunun bir hata veya kabul edilebilir bir sonuç olması durumunda, arayanın beklentilerine bağlı olduğunu düşünüyorum - bu yüzden seçimi arayana transfer ederim. Belki bir seçenek tanıtmak?

.CombinationsOf(4, CombinationsGenerationMode.Distinct, Options.AllowEmptySets)


10
Bununla nereye gideceğinize ulaşırken, davranışlarını değiştiren birçok seçeneğe sahip yöntemlerden kaçınmaya çalışıyorum. Ben zaten orada olan mod enum ile% 100 mutlu değilim; Bir yöntemin istisna davranışını değiştiren bir seçenek parametresi fikrini gerçekten sevmiyorum. Bir yöntemin bir istisna atması gerekiyorsa, atması gerektiği gibi hissediyorum; Bu istisnayı gizlemek istiyorsanız, bu sizin arama kodu olarak sizin kararınızdır ve kodumu doğru giriş seçeneğiyle yapabileceğiniz bir şey değildir.
anaximander

Arayan boş olmayan bir set beklerse, o zaman boş bir set işlemek veya bir istisna atmak arayan kişiye kalır. Callee söz konusu olduğunda, boş bir set mükemmel bir cevaptır. Ve boş setlerin iyi olup olmadığına dair farklı fikirlerle birden fazla arayanınız olabilir.
gnasher729

2

Açık bir cevap olup olmadığına karar vermek için iki yaklaşım vardır:

  • Önce bir seçenek, sonra diğeri varsayılarak kod yazın. Hangisinin pratikte en iyi olacağını düşünün.

  • Parametrelerin kesin olarak doğrulanmasını isteyip istemediğinizi belirtmek için bir "strict" boolean parametresi ekleyin. Örneğin, Java'nın , formatla tam olarak eşleşmeyen girişleri ayrıştırma girişimi için SimpleDateFormatbir setLenientyöntemi vardır . Elbette, varsayılanın ne olduğuna karar vermelisin.


2

Kendi analizinize dayanarak, boş setin geri dönüşü açıkça doğru gözüküyor - hatta bazı kullanıcıların gerçekten isteyebilecekleri ve bazı kullanımları yasaklayan tuzağa düşmemiş oldukları bir şeyi bile belirlediniz, çünkü onu kullanmak isteyenleri hayal bile edemezsiniz. bu taraftan.

Eğer gerçekten bazı kullanıcıların boşuna olmayan iadeleri zorlamak isteyebileceğini düşünüyorsanız, o zaman herkese zorlamak yerine, bu davranışı istemek için bir yol verin . Örneğin, şunları yapabilirsiniz:

  • Hangi eylemi kullanıcı için eylem gerçekleştiriyorsa onu bir yapılandırma seçeneği yapın.
  • Kullanıcının isteğe bağlı olarak işleve geçebileceği bir bayrak yap.
  • AssertNonemptyZincirlerine koyabilecekleri bir çek sağlayın .
  • Biri boş olmayan, diğeri olmayan iki işlev yapın.

bu, önceki 12
cevapta

1

Bu gerçekten, kullanıcılarınızın ne beklediğine bağlı. (Biraz ilgisiz) bir örnek için, kodunuz bölme gerçekleştirirse, bir istisna atabilir veya geri döndürebilir Infveya NaNsıfıra bölebilirsiniz. Ne doğru ne de yanlış.

  • Infbir Python kütüphanesine geri dönerseniz , insanlar gizleme hataları için size saldırırlar
  • bir Matlab kütüphanesinde bir hataya neden olursanız, insanlar verileri eksik değerlerle işlememediğiniz için size saldıracaklardır

Senin durumunda, son kullanıcılar için en az şaşırtıcı olan çözümü seçerdim. Setlerle ilgili bir kütüphane geliştirdiğiniz için, boş bir set, kullanıcılarınızın başa çıkmayı umduğu bir şey gibi gözüküyor, bu yüzden geri dönmek mantıklı bir şey gibi geliyor. Ancak yanılıyor olabilirim: bağlamı, buradaki herkesten daha iyi anlıyorsunuz, bu nedenle, kullanıcılarınızın her zaman boş olmayan sete güvenmelerini beklerseniz, hemen bir istisna atmalısınız.

Kullanıcının seçmesine izin veren çözümler ("katı" bir parametre eklemek gibi) kesin değildir, çünkü orijinal soruyu yeni bir eşdeğerle değiştirirler: "Hangi değer strictvarsayılan olmalıdır?"


2
Cevabımda NaN argümanını kullanmayı düşündüm ve fikrini paylaşıyorum. OP'nin etki alanını bilmeden daha fazlasını söyleyemeyiz
GameDeveloper

0

(Matematikte), bir küme üzerinde elemanlar seçtiğinizde, hiçbir eleman bulamayacağınız ve dolayısıyla boş bir küme elde edebileceğiniz yaygın bir kavramdır . Tabii bu yoldan gidersen, matematikle tutarlı olmalısın:

Ortak ayar kuralları:

  • Set.Foreach (yüklem); // boş kümeler için her zaman true değerini döndürür
  • Set.Exists (yüklem); // boş kümeler için her zaman false döndürür

Sorunuz çok ince:

  • Fonksiyonunuzun girişinin bir sözleşmeye saygı duyması gerekebilir : Bu durumda herhangi bir geçersiz girişin bir istisna yaratması gerekir, işte bu, fonksiyon normal parametreler altında çalışmıyor.

  • İşlev girişinin tam olarak bir küme gibi davranması gerekebileceği ve bu nedenle boş bir küme döndürebilmesi gerektiği olabilir.

Şimdi senin içinde olsam "Set" yoluna giderdim, ama büyük bir "AMA" ile.

"Hipotez yoluyla" sadece kız öğrencilerin olması gereken bir koleksiyonunuz olduğunu varsayalım:

class FemaleClass{

    FemaleStudent GetAnyFemale(){
        var femaleSet= mySet.Select( x=> x.IsFemale());
        if(femaleSet.IsEmpty())
            throw new Exception("No female students");
        else
            return femaleSet.Any();
    }
}

Artık koleksiyonunuz artık "saf bir set" değil, çünkü üzerinde bir sözleşmeniz var ve bu nedenle sözleşmenizi bir istisna dışında uygulamanız gerekiyor.

"Set" fonksiyonlarınızı saf bir şekilde kullandığınızda, boş set durumunda istisnalar atmamalısınız, fakat artık "saf set" olmayan koleksiyonlarınız varsa, uygun durumlarda istisnalar atmalısınız .

Her zaman daha doğal ve tutarlı hissettiren şeyleri yapmalısınız: bana göre bir küme kurallar koymaya uymalı, kümeler olmayan şeyler ise doğru şekilde düşünülmüş kurallara sahip olmalıdır.

Senin durumunda yapmak iyi bir fikir gibi görünüyor:

List SomeMethod( Set someInputSet){
    var result = someInputSet
        .CombinationsOf(4, CombinationsGenerationMode.Distinct)
        .Select(combo => /* do some operation to a combination */)
        .ToList();

    // the only information here is that set is empty => there are no combinations

    // BEWARE! if 0 here it may be invalid input, but also a empty set
    if(result.Count == 0)  //Add: "&&someInputSet.NotEmpty()"

    // we go a step further, our API require combinations, so
    // this method cannot satisfy the API request, then we throw.
         throw new Exception("you requsted impossible combinations");

    return result;
}

Ancak bu gerçekten iyi bir fikir değil, şu anda rastgele anlarda çalışma zamanında meydana gelebilecek geçersiz bir durumumuz var, ancak bu sorunla örtülü olduğundan, onu kaldıramayacağız, istisnayı bazı hizmet yönteminin içinde taşıyabileceğimize emin olabiliriz (bu tam olarak aynı kod, farklı yerlere taşındı), fakat bu yanlış ve temelde yapabileceğiniz en iyi şey , normal kurallara uymak .

Sadece yeni sorgulamalar ekleyerek, linq sorgulama yöntemlerini yazabildiğini göstermek için problemine değmez gibi görünüyor , eğer OP bize etki alanı hakkında daha fazla bilgi verirse, muhtemelen istisnanın gerçekten gerekli olduğu noktayı bulabileceğimize eminim (eğer hiç de, sorunun hiç bir istisna gerektirmemesi mümkündür).


Sorun, bir sorunu çözmek için matematiksel olarak tanımlanmış nesneler kullanıyor olmanızdır, ancak sorunun kendisi matematiksel olarak tanımlanmış bir nesneyi cevap olarak gerektirmeyebilir (burada bir liste döndürür). Her şey, sorunun nasıl çözüldüğüne bakılmaksızın, kapsülleme / bilgi gizleme olarak adlandırılan sorunun üst seviyesine bağlıdır.
GameDeveloper

"SomeMethod" cihazınızın artık bir set gibi davranmamasının nedeni, "Setler dışında" bir parça bilgi istemeniz, özellikle "&& someInputSet.NotEmpty ()"
GameDeveloper

1
HAYIR! Kadın sınıfında bir istisna atmamalısın. FemaleClassSadece kadınları olmadıkça (herkese açık bir şekilde oluşturulamıyor, yalnızca Oluşturucu sınıfı bir örnek verebilir) ve muhtemelen en az bir kadına sahip olmadıkça bir örneğini bile ALMAMANIZI zorlayan Oluşturucu desenini kullanmalısınız. . Ardından, FemaleClassargüman olarak kabul edilen yerin her yerindeki kodunuz , nesne yanlış durumda olduğundan istisnaları ele almak zorunda değildir.
ErikE

Bu sınıfın o kadar basit olduğunu varsayıyorsunuz, ön koşullarını sadece kurucu ile, gerçekte uygulayabiliyorsunuz. Argüman hatalı. Artık kadın sahibi olmayı yasaklarsanız, o zaman ya da sınıftan öğrenci çıkarmak için bir metoda sahip olamazsınız veya metotunuz 1 öğrenci kaldığında bir istisna yapmak zorunda kalır. Sen sadece sorunumu başka bir yere taşıdın. Mesele şu ki, "tasarım tarafından" sürdürülemeyen bir önkoşul / fonksiyon durumu her zaman olacağı ve kullanıcının bozulacağıdır: bu nedenle İstisnalar var! Bu oldukça teorik bir şey, umarım beğenen sizin değildir.
GameDeveloper

Olumsuz oy benim değil, eğer öyleyse, gurur duyardım . Dikkatlice ama mahkumiyetle oy kullandım. Sınıfınızın kuralı, içinde bir öğe olması GEREKEN ise ve tüm maddelerin belirli bir koşulu yerine getirmesi gerekiyorsa, o zaman sınıfın tutarsız bir durumda kalmasına izin vermek kötü bir fikirdir. Sorunu başka bir yere taşımak tam olarak benim niyetim! Ben istiyorum sorun değil kullanımı sırasında, zaman bina oluşmak üzere. Yapıcı atma yerine bir Builder sınıfı kullanmanın amacı, tutarsızlıklar yoluyla birçok parça ve parçada çok karmaşık bir durum oluşturabilmenizdir.
ErikE
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.