Bir Enum 0 veya 1 ile başlamalı mı?


136

Aşağıdaki Numarayı tanımladığımı düşünün:

public enum Status : byte
{
    Inactive = 1,
    Active = 2,
}

Enum kullanmak için en iyi uygulama hangisidir? 1Yukarıdaki örnekte olduğu gibi başlıyorsa veya 0şu şekilde (açık değerler olmadan) başlıyorsa :

public enum Status : byte
{
    Inactive,
    Active
}

13
Gerçekten onları açıkça numaralandırmanız gerekiyor mu?
Yuck

164
Numaralandırmalar, böyle şeyler önemli olmayacak şekilde oluşturuldu.
BoltClock

9
@Daniel - arrgh hayır! Bir booleanın yapacağını düşündüğünüzde bir enum kullanmak, bir enum düşünürken bir boolean kullanmaktan daha iyidir.
AAT

22
@Daniel FileNotFound değeri nedeniyle, elbette
Joubarc

5
xkcd.com/163 , numaralandırma için dizin dizinleri için olduğundan daha iyi uygulanır.
leftaroundabout

Yanıtlar:


161

Çerçeve Tasarımı Yönergeleri :

En️ Basit numaralandırmalarda sıfır değeri girin.

Değeri "Hiçbiri" gibi bir şey olarak adlandırmayı düşünün. Böyle bir değer bu belirli numaralandırma için uygun değilse, numaralandırma için en yaygın varsayılan değerin altında sıfır değeri atanmalıdır.

Çerçeve Tasarım Yönergeleri / Bayrak Numaralandırmalarının Tasarımı :

Flag Değer "tüm bayraklar temizlenir" i temsil etmediği ve bir sonraki kılavuzda belirtildiği şekilde uygun şekilde adlandırılmadığı sürece, bayrak enum değerlerini sıfırlamaktan KAÇININ.

✔️ Bayrak numaralandırmalarının sıfır değerini HAYIR adlandırın Yok. Bir bayrak numaralandırma için, değer her zaman "tüm bayraklar temizlenir" anlamına gelmelidir.


28
Erken başarısız olun: 'Hiçbiri' uygun değilse, ancak mantıksal varsayılan değeri yoksa, yine de sıfır değeri (ve 'Hiçbiri' veya 'Geçersiz' olarak adlandırılır) diyorum, bu numaralandırmanın bir sınıf üyesi doğru şekilde başlatılmazsa, başlatılmamış değer kolayca tespit edilebilir ve switchifadelerde a attığım defaultbölüme atlar InvalidEnumArgumentException. Aksi takdirde, bir program, geçerli ve fark edilmeden sıfır numaralandırma sıfır değeriyle çalışmaya devam edebilir.
Allon Guralnek

1
@Allon Yalnızca geçerli olduğunu bildiğiniz enum değerlerini vermek ve sonra ayarlayıcı ve / veya yapıcıda geçersiz değerleri kontrol etmek daha iyi görünüyor. Bu şekilde, geçersiz verileri olan bir nesnenin bilinmeyen bir süre boyunca var olmasına izin vermek ve daha sonra öğrenmek yerine, bazı kodların doğru çalışmadığını hemen bilirsiniz. 'Hiçbiri' geçerli bir durumu temsil etmedikçe, kullanmamalısınız.
wprl

@SoloBold: Bu, bir enum sınıfı üyesini bir kurucuda başlatmayı unutmadığınız bir vaka gibi görünür. Sıfırlamayı veya doğrulamayı unutursanız, hiçbir doğrulama size yardımcı olmaz. Ayrıca, herhangi bir kurucuya sahip olmayan, ancak nesne başlatıcılara dayanan basit DTO sınıfları vardır . Böyle bir böceği avlamak son derece acı verici olabilir. Bununla birlikte, kullanılmayan bir numaralandırma değeri eklemek çirkin bir API gerektirir. Kamu tüketimine yönelik API'lar için bundan kaçınırım.
Allon Guralnek

@Allon Bu iyi bir nokta, ancak ayarlayıcı işlevindeki sıralamaları doğrulamanız ve ayarlayıcı hiç çağrılmadıysa alıcıdan atmanız gerektiğini savunuyorum. Bu şekilde bir hata noktanız olur ve tasarımı ve kodu basitleştiren geçerli bir değere sahip olan alanı planlayabilirsiniz. Zaten iki sentim.
wprl

@SoloBold: Otomatik olarak uygulanan 15 özelliğe sahip bir DTO sınıfı düşünün. Gövdesi 15 satır uzunluğundadır. Şimdi aynı sınıfın düzenli özelliklere sahip olduğunu hayal edin. Herhangi bir doğrulama mantığı eklemeden önce minimum 180 satır. Bu sınıf yalnızca dahili olarak yalnızca veri aktarımı amacıyla kullanılır. Hangisini sürdürmeyi tercih edersiniz, 15 satır sınıfı veya 180+ satır sınıfı? Özlüğin değeri vardır. Ama yine de, her iki stilimiz de doğru, sadece farklı. (Sanırım AOP burada tartışıyor ve tartışmanın her iki tarafını da kazanıyor).
Allon Guralnek

66

Sanırım, açıkça onları numaralandırmamak için söylenen çoğu cevapla anlaşamadım. Onları her zaman açıkça numaralandırıyorum, ancak çoğu durumda onları bir tamsayı değeri olarak depolandıkları bir veri akışında ısrar ettim. Değerleri açıkça eklemez ve sonra yeni bir değer eklerseniz, serileştirmeyi kırabilir ve daha sonra eski kalıcı nesneleri doğru bir şekilde yükleyemezsiniz. Bu değerlerin kalıcı bir depo herhangi bir tür yapacaksanız o zaman açıkça değerleri ayarlamayı tavsiye ediyoruz.


9
+1, kabul edildi, ancak yalnızca kodunuzun harici bir nedenden ötürü tamsayıya bağlı olması durumunda (örn. Serileştirme). Diğer her yerde sadece çerçevenin işini yapmasına izin vermelisiniz. Dahili olarak tamsayı değerlerine güveniyorsanız, muhtemelen yanlış bir şey yapıyorsunuzdur (bkz: çerçevenin işi yapmasına izin verme).
Matthew Scharley

3
Enum metnine devam etmeyi seviyorum. Veritabanını çok daha kullanılabilir imo yapar.
Dave

2
Normalde, serileştirildiklerinde bile değerleri açıkça ayarlamanız gerekmez. sonunda DAİMA yeni değerler eklemeniz yeterlidir. bu serileştirme sorunlarını çözecektir. aksi halde veri deponuzun bir sürümüne ihtiyacınız olabilir (örn. değerleri okurken / yazarken davranışı değiştirmek için bir sürüm içeren bir dosya başlığı) (veya hatıra modeline bakın)
Beachwalker

4
@Dave: Numaralandırma metinlerinin kutsal olduğunu açık bir şekilde belgelemediğiniz sürece, gelecekteki bir programcı bir adı daha açık veya bazı adlandırma kurallarına uyacak şekilde ayarlamaya karar verirse kendinizi başarısızlık için ayarlarsınız.
supercat

1
@pstrjds: Sanırım bir stilistik ticaret kapalı - disk alanı ucuz olsa da, sürekli enum değerleri arasında dönüşüm ve harcanan bir db ararken nispeten pahalı (iki kez yani bir veritabanı veya benzer bir şey karşı bir raporlama aracı kurulum varsa) . Abotu alanından endişe ediyorsanız, daha yeni SQL sunucu sürümleriyle sıkıştırılmış bir veritabanınız olabilir, bu da "SomeEnumTextualValue" ifadesinin 1000 kez daha fazla yer kaplayacağı anlamına gelir. Tabii ki bu tüm projeler için işe yaramayacak - bir değiş tokuş. Bant genişliği endişesi erken optimizasyon gibi kokuyor, belki!
Dave

15

Bir Enum bir değer türüdür ve açıkça başlatılmamışsa varsayılan değeri (örneğin bir sınıftaki Enum alanı için) 0 olur.

Bu nedenle genellikle tanımlanmış bir sabit olarak 0'a sahip olmak istersiniz (örn. Bilinmiyor).

Örneğinizde, isterseniz Inactive , varsayılan değer sıfır değerine sahip olmalıdır. Aksi takdirde, bir sabit eklemeyi düşünebilirsiniz.Unknown .

Bazı insanlar sabitleriniz için değerleri açıkça belirtmemenizi tavsiye etti. Muhtemelen çoğu durumda iyi tavsiye, ancak bunu yapmak isteyeceğiniz bazı durumlar vardır:

  • Bayraklar numaralandırır

  • Değerleri harici sistemlerle birlikte kullanılan numaralandırmalar (örn. COM).


Ben bayrakları Çeteleler çok daha okunabilir ne zaman olduğunu tespit ettik yok açıkça değerlerini ayarlayın. - Derleyici sizin için ikili matematik yapmak izin eğilimli yol daha az hata. (yani [Flags] enum MyFlags { None = 0, A, B, Both = A | B, /* etc. */ }, daha okunabilir [Flags] enum MyFlags { None = 0, A = 1, B = 2, Both = 3, /* etc */ }.)
BrainSlugs83

1
@ BrainSlugs83 - Bunun genel durumda nasıl yardımcı olacağını görmüyorum - örneğin [Flags] enum MyFlags { None=0, A, B, C } sonuçlanırken [Flags] enum MyFlags { None=0, A=1, B=2, C=3 }, Bayraklar sıralaması için genellikle C = 4 istersiniz.
Joe

14

Değiştirmek için belirli bir nedeniniz yoksa, numaralandırmaları sıfırdan başlayan varsayılan değerleriyle bırakın.

public enum Status : byte
{
    Inactive,
    Active
}

6

En iyi uygulama onları numaralandırmak ve örtük olmasına izin vermek olduğunu söyleyebilirim - bu 0'dan başlayacak.


6

0 ile boole türü bir enum başlatacağım.

"Inative", "Inactive" dışında bir şey ifade etmediği sürece :)

Bu, onlar için standardı korur.


6

Bunları nasıl kullandığınıza bağlı olarak söyleyebilirim. Enum işaretlemek için Nonedeğer için 0'a sahip olmak iyi bir uygulamadır , şöyle:

[Flags]
enum MyEnum
{
    None = 0,
    Option1 = 1,
    Option2 = 2,
    Option3 = 4,
    All = Option1 | Option2 | Option3,
}

Numaralandırmanızın bir veritabanı arama tablosuna eşlenmesi muhtemel olduğunda, 1 ile başlayacağım. Profesyonelce yazılmış kod için çok önemli olmamalıdır, ancak bu okunabilirliği artırır.

Diğer durumlarda 0 veya 1 ile başlayıp başlamadıklarına hiç dikkat etmeden olduğu gibi bırakırdım.


5

Eğer çiğ değerlerini kullanmak için iyi bir neden yoksa, sadece hiç örtük değerleri kullanarak ve bunları referans olmalıdır Status.Activeve Status.Inactive.

Yakalama, verileri düz bir dosyada veya DB'de depolamak veya başka birinin oluşturduğu düz bir dosya veya DB kullanmak isteyebileceğinizdir. Kendiniz yapıyorsanız, numaralandırma Enum'un ne için kullanıldığına uydurun.

Veriler size ait değilse, elbette orijinal geliştiricinin numaralandırma şeması olarak kullandığı her şeyi kullanmak isteyeceksiniz.

Enum'u bir bayrak kümesi olarak kullanmayı planlıyorsanız, aşağıdakilere değecek basit bir kural vardır:

enum Example
{
  None      = 0,            //  0
  Alpha     = 1 << 0,       //  1
  Beta      = 1 << 1,       //  2
  Gamma     = 1 << 2,       //  4
  Delta     = 1 << 3,       //  8
  Epsilon   = 1 << 4,       // 16
  All       = ~0,           // -1
  AlphaBeta = Alpha | Beta, //  3
}

Değerler ikisinin gücü olmalıdır ve bit kaydırma işlemleri kullanılarak ifade edilebilir. None, açıkçası olması gerekir 0, ancak Alldaha az açıktır -1. ~0İkili olumsuzlanmasıdır 0her bit kümesi olan bir sayı ve sonuçlar 1, bir değeri temsil eder-1 . Bileşik bayraklar için (genellikle kolaylık sağlamak için kullanılır) diğer değerler bitsel veya operatör kullanılarak birleştirilebilir |.



3

Belirtilmezse numaralandırma 0'dan başlar.

Mümkün olanların çoğu kez serileştirildiğinden ve bir dize olarak değil, bir int olarak depolandığından, açık olmak önemlidir.

Veritabanında saklanan tüm numaralandırmalar için, bakım sırasında kaymayı ve yeniden atamayı önlemek için seçenekleri her zaman açıkça numaralandırırız.

Microsoft'a göre önerilen kural, başlatılmamış veya en yaygın varsayılan değeri temsil etmek için ilk sıfır seçeneğini kullanmaktır.

Aşağıda, 0 yerine 1'de numaralandırmaya başlamak için bir kısayol bulunmaktadır.

public enum Status : byte
{
    Inactive = 1,
    Active
}

Numara değerlerinde bit işleçlerini kullanmak için bayrak değerleri ayarlamak isterseniz, sıfır değerinde numaralandırmaya başlamayın.


2

1'den başlarsanız, eşyalarınızı kolayca alabilirsiniz.

{
    BOX_THING1     = 1,
    BOX_THING2     = 2,
    BOX_NUM_THING  = BOX_THING2
};

0'dan başlarsanız, ilkini başlatılmamış şeyler için değer olarak kullanın.

{
    BOX_NO_THING   = 0,
    BOX_THING1     = 1,
    BOX_THING2     = 2,
    BOX_NUM_THING  = BOX_THING2
};

5
Üzgünüm Jonathan. Bence bu öneri aklımda biraz "eski okul" (bir tür sözleşme düşük seviyeli c yıllardan geliyor). Bu numaralandırma hakkında bazı ek bilgi "gömmek" için hızlı bir çözüm olarak Tamam ama bu büyük sistemlerde iyi bir uygulama değildir. Kullanılabilir değerlerin sayısı vb. Hakkında bilgiye ihtiyacınız varsa bir numaralandırma kullanmamalısınız. Peki ya BOX_NO_THING1? Ona BOX_NO_THING + 1 verir misiniz? Numaralandırmalar, amaçlandıkları şekilde kullanılmalıdır: "Konuşan" adlarla temsil edilen belirli (int) değerler.
Beachwalker

Hm. Eski okul olduğunu düşünüyorsunuz çünkü MicrosoftBumpyCaseWithLongNames yerine tüm büyük harfleri kullandım. Her ne kadar yinelenen bir XyzNumDefsInMyEnum tanımına ulaşana kadar döngüleri kullanmaktan daha iyi yineleyiciler kabul ediyorum.
Jonathan Cline IEEE

Bu C # çeşitli yollarla korkunç bir uygulamadır. Şimdi numaralarınızı doğru şekilde almaya gittiğinizde veya onları doğru şekilde numaralandırmaya çalıştığınızda, ekstra, yinelenen bir nesne elde edersiniz. Ayrıca .ToString () çağrısını diğer şeylerin yanı sıra potansiyel olarak belirsiz hale getirir (modern serileştirmeyi bozar).
BrainSlugs83

0

Her şeyden önce, bir nedenden dolayı belirli değerleri belirtmedikçe (sayısal değerin başka bir yerde anlamı varsa, yani Veritabanı veya harici hizmet), sayısal değerleri hiç belirtmeyin ve açık olmasına izin vermeyin.

İkincisi, her zaman sıfır değerine sahip bir öğeniz olmalıdır (bayrak olmayan numaralandırmalarda). Bu öğe varsayılan değer olarak kullanılacaktır.


0

Bunları bir diziye veya listeye endeks olarak kullanmak veya başka bir pratik neden (bitsel işlemlerde kullanmak gibi) gibi bir neden olmadıkça 0'da başlatmayın.

Sizin enumbu ihtiyacı tam olarak nerede başlanmalıdır. Sıralı olması da gerekmez. Değerler, açıkça belirlenmişlerse, bazı anlamsal anlamları veya pratik düşünceyi yansıtmaları gerekir. Örneğin, enum"duvardaki şişeler" in bir tanesi 1'den 99'a kadar numaralandırılmalıdır.enum karşılık 4'lü kuvvetler muhtemelen 4'ten başlamalı ve 16, 64, 256 vb. devam etmelidir.

Ayrıca, değere sıfır değerli bir eleman eklemek, enumyalnızca geçerli bir durumu temsil ediyorsa yapılmalıdır. Bazen "hiçbiri", "bilinmiyor", "eksik" vb. Geçerli değerlerdir, ancak çoğu zaman değildir.


-1

Numaralarımı 0'da başlatmak istiyorum, çünkü bu varsayılan, ancak -1 değeri olan Bilinmeyen bir değer de eklemek istiyorum. Bu daha sonra varsayılan olur ve bazen hata ayıklamaya yardımcı olabilir.


4
Korkunç bir fikir. Bir değer türü olarak, numaralandırmalar her zaman sıfırlanır. Bilinmeyen veya başlatılmamış bir değeri temsil edecekseniz 0 olması gerekir. Varsayılanı -1 olarak değiştiremezsiniz, sıfır doldurma CLR boyunca sabit kodlanır.
Ben Voigt

Ah, bunun farkında değildim. Ben çıkartma / başlatma sırasında genellikle bir enum değeri / özelliğinin değerini ayarlar. İşaretçi için teşekkürler.
Tomas McGuinness
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.