Sihir sayılarına null türleri tercih edilebilir mi?


22

Son zamanlarda bir iş arkadaşınızla biraz tartışma yaşadım. Özellikle C # kullanıyoruz, ancak bu, null türlerine sahip herhangi bir dil için geçerli olabilir. Örneğin, bir maksimum değeri temsil eden bir değeriniz olduğunu söyleyin. Ancak, bu maksimum değer isteğe bağlıdır. Boş bir sayının tercih edilebilir olacağını savunuyorum. İş arkadaşım, emsali olduğuna göre, sıfır kullanımını destekliyor. Verilen, ağ soketleri gibi şeyler sınırsız bir zaman aşımını temsil etmek için genellikle sıfır kullandı. Bugün soketlerle ilgili bir kod yazacak olsaydım, şahsen nulla değer kullanırdım, çünkü NO zaman aşımı olmadığı gerçeğini daha iyi göstereceğini düşünüyorum.

Hangi temsil daha iyidir? Her ikisi de "hiçbiri" anlamına gelen bir koşulu kontrol etmeyi gerektirir, ancak boş bir tipin amacını biraz daha iyi taşıdığına inanıyorum.


6
Bir sayı kullanılıyorsa, doğrudan koda değil sabit bir sayıya koyun.
Renato Dinhani

@ RenatoDinhaniConceição bu genel bir kural olamaz. Aksi takdirde her şeyi softcoding kodlarsınız .
Simon Bergot

Yanıtlar:


24

Düşünmek:

  • Dil,

  • Çerçeve,

  • Bağlam.

1. Dil

∞ kullanmak azami bir çözüm olabilir.

  • Örneğin, JavaScript bir sonsuzluğa sahiptir. C # yapmaz.

  • Mesela Ada'nın aralıkları var. C # yapmaz.

C # 'da var int.MaxValue, ama senin durumunda kullanamazsın. int.MaxValuemaksimum tamsayı, 2,147,483,647'dir. Kodunuzda, bir şey patlamaya başlamadan önce maksimum bir baskı gibi, maksimum bir değere sahip olursanız, 2.147.483.647'yi kullanmanın bir anlamı yoktur.

2. Çerçeve

.NET Framework bu noktada oldukça tutarsız ve sihirli değerlerin kullanımı eleştirilebilir.

Örneğin, "Hello".IndexOf("Z")bir sihirli değer döndürür -1. Bu belki de (bunu yapar?) Kolaylaştırır sonucu işlemek için:

int position = "Hello".IndexOf("Z");
if (position > 0)
{
    DoSomething(position);
}

özel bir yapı kullanmak yerine:

SearchOccurrence occurrence = "Hello".IndexOf("Z");
if (occurrence.IsFound)
{
    DoSomething(occurrence.StartOffset);
}

ama hiç sezgisel değil. Neden -1ve değil -123? Yeni başlayanlar ayrıca yanlışlıkla 0"Bulunamadı" anlamına da gelebilir ya da sadece yanlış yazım yapabilir (position >= 0).

3. Bağlam

Kodunuz ağ soketlerinde zaman aşımları ile ilgiliyse, tutarlı olma uğruna herkes tarafından on yıllarca kullanılan bir şeyin kullanılması kötü bir fikir değildir . Özellikle, 0bir zaman aşımı için çok açık: sıfır olamaz bir değer. Bu durumda özel bir sınıf kullanmak işlerin anlaşılmasını zorlaştırabilir:

class Timeout
{
    // A value indicating whether there is a timeout.
    public bool IsTimeoutEnabled { get; set; }

    // The duration of the timeout, in milliseconds.
    public int Duration { get; set; }
}
  • Doğru Durationise 0 olarak ayarlayabilir miyim IsTimeoutEnabled?
  • Eğer IsTimeoutEnabledyanlış ise Duration100'e set edersem ne olur ?

Bu birden fazla hataya yol açabilir. Aşağıdaki kod parçasını hayal edin:

this.currentOperation.Timeout = new Timeout
{
    // Set the timeout to 200 ms.; we don't want this operation to be longer than that.
    Duration = 200,
};

this.currentOperation.Run();

İşlem on saniye boyunca devam eder. TimeoutSınıfın dökümanlarını okumadan bu kodda neyin yanlış olduğunu görebiliyor musunuz?

Sonuç

  • nullDeğerin burada olmadığı fikrini iyi ifade eder. Sağlanmadı. Müsait değil. Ne sayı, ne de sıfır / boş dize veya hiç. Maksimum veya minimum değerler için kullanmayın.

  • int.MaxValuedilin kendisi ile yakından ilgilidir. Kullanmayın int.MaxValuemaksimum hız limiti için Vehiclebir uçağın, vs. sınıf veya maksimum kabul edilebilir bir hızda

  • -1Kodunuzdaki gibi sihirli değerlerden kaçının . Yanıltıcılar ve kodlarda hatalara yol açarlar.

  • Belirlenen minimum / maksimum değerlerle, daha basit bir şekilde kendi sınıfınızı oluşturun. Örneğin VehicleSpeedolabilir VehicleSpeed.MaxValue.

  • Daha önce herhangi bir kılavuza uymayın ve çoğu insan tarafından bu alana kod yazarken kullanılan, çok özel bir alanda yıllarca süren genel bir kuralsa, sihirli değerleri kullanmayın.

  • Yaklaşımları karıştırmayı unutma. Örneğin:

    class DnsQuery
    {
        public const int NoTimeout = 0;
    
        public int Timeout { get; set; }
    }
    
    this.query.Timeout = 0; // For people who are familiar with timeouts set to zero.
    // or
    this.query.Timeout = DnsQuery.NoTimeout; // For other people.
    

İnity Sonsuzluğu içeren kendi türünüzü oluşturabilirsiniz. Burada intyalnızca yerel türden bahsediyorum .


1
"Herkesin on yıllar boyunca tutarlı olma uğruna kullandığı bir şeyi kullanmak kötü bir fikir değildir" / "Daha önceki herhangi bir kılavuza uymayın ve eğer yıllarca çok özel bir alanda yapılan genel bir kuralsa, sihirli değerleri kullanın. çoğu kişi bu alana kod yazıyor. " - Bir yerde yazım hatası var galiba?
deworde

1
@deworde MainMa'nın kendisinin üzerinde yazan kurallara atıfta bulunduğunu düşünüyorum.
Joshua Drake 19

1
İndexOf örneğine katılmıyorum, çünkü -1 kesinlikle Z'nin olduğu gibi dizginin dışındaydı .
Joshua Drake

5
"JavaScript, örneğin bir sonsuzluk vardır. C # yok." - ha?
BlueRaja - Danny Pflughoeft 20:30

"1 sınıfını oluştur" için özellikle + 1 önerdim. Herhangi bir çıplaklık intsorunu sınırlamak için tür hakkında yeterince açıklamada bulunmadığında, daha fazla bilgi içeren yeni bir yapı düşünün (örneğin sihirli değerleri temsil eden yapı örnekleri veya belirtmek için enum). Veya sözleşme programlamasını veya başka çözümleri düşünün, ancak özel bir yapının en basit olduğunu düşünüyorum.
CodexArcanum

12

Null sihirli bir sayıdan daha iyi değildir.

Önemli olan, eğer böyle bir değere sahip olmanız gerekiyorsa, sihirli etkileri olan değerleri isimlendirmek ve bu isimlerin tanımlarının, sihirli değere ve wtf'lere çarpan herkesin göreceği bir yer olduğundan emin olmaktır.

if (timeout == 4298435) ... // bad.
if (timeout == null) ... // bad.
if (timeout == NEVER_TIME_OUT) ... // yay! puppies and unicorns!

2
Tamam, belki de dile daha fazla bağlıdır, fakat C # 'da muhtemelen şunu yapardınız: eğer null ile doğrudan bir karşılaştırma yapmak yerine eğer (timeout.HasValue).
Matt H

2
Null, sihir sayısından daha kötü değildir. Sihirli sayılarla, sihirli sayının ne olduğunu asla bilemezsiniz ... 0, -1 veya başka bir şey olabilir. boş sadece boş.
marco-fiset,

9
Boş değerin yokluğu demektir. Bu, pek çok sihirli sayının ifade etmek istediği bir kavram. Null değerine sahip boş bir tür kullanabilmek, bir veri türü için olası bir değer arasından isteğe bağlı bir değer seçmekten çok daha iyi bir çözümdür.
26

2
Türünüzde "null" varsa, sihirli değeriniz olarak "null" kullanmak iyidir. Önemli olan, ADI yapmak. Çünkü gelecek olan adamı vurmak, ne demek istediğini bilmeyecek. Boş, "henüz tanımlanmadı", "henüz belirtilmemiş", "" veri yapısını oluşturan koddaki hata "veya başka herhangi bir sayı anlamına gelebilir. Sadece bir isim, bir sonraki kodlayıcının, bu değerin orada olmak istediğini ve tetiklemek için ne tür bir davranışı kastettiğini bilmesini sağlar.
mjfgates

1
@CodeInChaos: Her ikisini de yapabileceğinizi biliyorum, ancak HasValue'yu tercih ediyorum. Aslında, genel olarak null büyük bir hayranı değilim, ancak HasValue kullanan nulla türleri, hayranı olduğum bir Option / Belki de bana biraz daha yakın geliyor.
Matt H

10

MAGIC_NUMBERmümkün olan her yerde kesinlikle koddan kaçınılmalıdır. nullniyetin çok daha net bir ifadesidir.


6

C # 'da, çoğu CLR sınıfının statik bir Emptyüyesi vardır:

  • System.String.Empty
  • System.EventArgs.Empty
  • System.Guid.Empty
  • System.Drawing.Rectangle.Empty
  • System.Windows.Size.Empty

Bu, boş bir nesne oluşturmak için bir sihirli değer kullanıp kullanmayacağınızı ya da null kullanıp kullanmayacağınızı hatırlamanıza engel olur.

Peki ya bunun gibi basit bir değer türüyle uğraşıyorsanız int? Bu durumda, İlkel Takıntıya kurban edilip edilmediğinizi düşünün . Görünüşe göre basit sayısal özelliğiniz, Emptyüyeyi belirtmenize ve aynı zamanda bu değere özgü başka davranışlar eklemenize izin verecek kendi sınıfından veya yapısından faydalanabilir .


3

Bu durumda, boş değer, maksimum olmadığını belirtmek için harika bir yoldur. Genel olarak, özel durum, söz konusu değerin geçerli olmadığı, yapılandırdığı özelliği istemediğiniz anlamına gelmediği durumlarda null bunun iyi bir göstergesidir.

Özel durumları temsil etmek için null kullanımıyla ilgili bir sorun, yalnızca bir boş değerin olması ve çok sayıda özel durum olabileceğidir. Bu durumda, özel bir durumu gösterebilecek veya int değerini normal şekilde kullanabilecek bir numaralandırma ek bir parametre olarak iletilir. (Bu aslında Null değerinin <> sizin için yaptığı şeydir, ancak enum yerine bir boole kullanıyor ve parametreleri tek bir yapı halinde birleştiriyor.)


3

Bu durumda, null türünün mükemmel bir anlam ifade ettiğini düşünüyorum.

Boş değerin yokluğu demektir. Bu, 0 değerine sahip bir sayıdan açıkça farklı bir kavramdır.

"Size bir değer vermezsem, maksimum değeri kullanın" demek istiyorsanız, boşuna çevirmek bunu ifade etmenin tam doğru yoludur.


1

Boş: ortak hata değeri, belirtilmemiş, geçersiz veya değer yokluğu.

Sıfır: Gerçek, ancak mutlaka mantıklı veya sezgisel bir değer (bu bağlamda). Ayrıca ilklendirmede ortak bir değer.

Sorununuz bağlamında, timeoutInMillisecondsözellik isteğe bağlıdır ve bu yaklaşımın ek yükünün bir seçenek olarak diskalifiye edeceğinden söz edilmez.

Sonuç: İstisnalar var ve çözümler dillere ve etki alanlarına göre değişiyor; bu durumda Null'ı seçerdim. Bazı insanların bunu yanlış anladığı yer (inanırım) verileri arayüzden iyi ayırmadıkları zamandır. Herhangi bir müşteriden, bu özel değerlerin nasıl kullanılacağını / kullanıldığını belirlemek için belgeleri (veya uygulamaları) okumasını beklerler - özel durumlar müşterinin programına sızar ve bu oldukça belirsiz olabilir. İyi bir soyutlama katmanı ekleyerek kullanım daha net olabilir.


0

Null kullanmaktan daha kötü MagicNumber. Null, daha iyi ifade edilen fikri temsil eder, ancak platformlar arasında nasıl davrandığı konusunda tutarlı değildir, MagicNumberher zaman yararlı olanla aynı şekilde çalışır.

çevreye / dile bağlı olarak kullanılabilir

  • sadece 0 ol
  • yasal bir değer olmayabilir
  • Üç yollu mantık nedeniyle beklenmeyen sonuçlar üretebilir

MagicNumber her zaman aynı şekilde davranır.


0

Sihirli numarayı kontrol etmeyi unutursanız (doğru şekilde gerçekleşir), o zaman bir sihirli numara saçma sapan verilerle bir süre daha devam eder. En kısa zamanda bir istisnaya neden olan bir boş değere sahip olmak çok daha iyidir.


-1

Null, sihirli bir sayıya tek alternatif değil.

public static int NO_TIMEOUT = 0;  // javaish

Null kötüdür. Yukarıdaki örnekte, kodun bir null ile başa çıkabileceğinden açıkça kurtulmanız mümkün olabilir. Ancak genel olarak boşa geçmeye başladığınızda ne olduğu, er ya da geç boş bir işaretçi istisnası elde etmenizdir. Kodu ilk yazdığınızda gerçekleşmeyebilir, ancak kod yalnızca ilk sürümden çok daha uzun süre korunur. Genellikle, orijinal geliştiriciler kadar sistem hakkında çok fazla şey bilmeyen insanlar tarafından sağlanır.

Scala (örneğin), Option sınıfında hoş bir alternatiftir. Option sınıfı iki değerden birine sahiptir; bazıları - gerçekten istediğiniz değeri tamamlar ve Yok - hiçbir değeri yoktur.

Bu, herhangi bir geliştirici için bir değer olamayacağı ve bunun için daha iyi bir kodun olduğu açıkça görülüyor. Zaten açıkça belli etmeli.

Ve tüm sihirli sayılar bir sorun değil. Bağlam 0, 1, 1024'e bağlı olarak hepsi açık olabilir. 347? Evet, kaçınmanız gereken şey. :-)


4
-1: "Boş" kötüdür.
deworde

4
Bir sayı için bir takma ad tanımlamak, hala bir sihirli sayı olduğu gerçeğini değiştirmez.
26

Belki de benden farklı bir sihir sayısının tanımı vardır. Lütfen en.wikipedia.org/wiki/… adresini ziyaret edin
Jon Strayer

1
Burada Jon Strayer ile aynı fikirdeyim. Null, ADT'leri gerçekten desteklemeyen bir dilde bir ADT örneğidir. OP muhtemelen buradan kurtulabilir ama genel olarak başarısız olan herhangi bir dili biraz programcı olduğunu düşünüyorum.
Jeremy Wall,
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.