Menu

C# Enum: Değerler, ToString, Parse, Flags ve Dolaşma

C#'ta enum'lar nasıl çalışır: adlandırılmış sabitler bildirmek, alttaki tamsayı değerleri ve cast, Parse ve TryParse ile enum'u string'e ve string'i enum'a çevirmek, tüm değerleri listelemek, bitsel operatörler ve HasFlag ile [Flags], enum üzerinde switch ve tanımsız değerleri ele almak.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Bir enum (numaralandırma), değerleri sabit bir adlandırılmış sabitler kümesi olan bir tiptir: sipariş durumları, haftanın günleri, log seviyeleri. Altta her ad bir tamsayıdır, ama tip sistemi bir OrderStatus'un düz bir int ile ya da başka bir enum ile karıştırılmasını önler.

Bir enum bildirmek ve kullanmak

Üye adlarını süslü parantezler içinde listeleyin. Varsayılan olarak ilki 0'dır ve sonraki her biri bir fazladır:

Çıktı:

Paid
On its way
True
2

Enum gerçek bir tiptir: OrderStatus alan bir metot yanlışlıkla 3 ile ya da bir LogLevel ile çağrılamaz. Enum'lar değer tipleridir, bu yüzden asla null olmazlar ve == ile değere göre karşılaştırılırlar.

Açık değerler ve alttaki tip

Sayıları kendiniz atayabilirsiniz. Sayı programınızın dışına çıktığında (bir veritabanı sütunu, bir HTTP durumu, bir dosya biçimi) bu önemlidir, çünkü o zaman yeniden numaralandırmak saklanan veriyi bozar:

Çıktı:

404
Created
418
1
Byte

Dikkat edilecek iki şey. Bir int'i bir enum'a cast etmek asla başarısız olmaz: (HttpStatus)418 yalnızca bir adı olmayan geçerli bir değerdir ve sayı olarak yazdırılır. Ve alttaki tip herhangi bir tamsayı tipi (byte, short, long, ...) olabilir; bu yalnızca depolamaya duyarlı kod için önemlidir, int varsayılandır ve neredeyse her zaman doğru seçimdir.

Sonradan üye eklediğinizde onları sona ekleyin ya da açık değerler verin. Paid ile Shipped arasına Refunded eklemek ondan sonraki her üyenin numarasını sessizce değiştirir.

Enum'dan string'e

ToString() üye adını döndürür; Console.WriteLine ve string interpolation'ın kullandığı da budur. Biçim string'leri çıktıyı değiştirir:

Çıktı:

Warning
2
00000002
[Warning]
Error
Error
Needs attention

Üye adları tanımlayıcılardır, bu yüzden boşluk içeremezler ve çevrilmezler. Kullanıcılara gösterilen metin için değerleri Label'ın yaptığı gibi kendiniz ya da bir Dictionary<LogLevel, string> ile eşleyin. Bazı kod tabanları her üyeye bir [Description("Needs attention")] özniteliği koyar ve onu reflection ile okur; reflection ve öznitelikler sayfası bu aramanın nasıl çalıştığını gösterir.

String'den enum'a: Parse ve TryParse

Enum.Parse bir adı tekrar bir değere çevirir ve hiçbir şey eşleşmezse ArgumentException fırlatır. Enum.TryParse ise bunun yerine false döndürür; kontrol etmediğiniz her girdi için istediğiniz budur:

Çıktı:

Large
Medium
Parse threw ArgumentException for Huge
small  parsed=True  value=Small  defined=True
XL     parsed=False value=Small  defined=True
2      parsed=True  value=Large  defined=True
7      parsed=True  value=7      defined=False

Son iki satır tuzaktır. İki metot da sayısal string'leri kabul eder, bu yüzden "7" adı olmayan bir Size'a başarıyla parse edilir. Ve başarısız bir TryParse sonucu 0'a ayarlar; burada bu, geçerli görünen Small'dur. Metin bir sorgu string'inden, bir yapılandırma dosyasından ya da bir formdan geldiğinde her zaman hem dönüş değerini hem de Enum.IsDefined'ı kontrol edin:

if (Enum.TryParse(input, true, out Size size) && Enum.IsDefined(typeof(Size), size))
{
    // safe to use size
}

.NET Core 2.0 ve sonrası cast gerektirmeyen generic bir Enum.Parse<Size>("Large") ekler.

Tüm değerleri listelemek

Enum.GetValues her üyeyi sayısal değere göre sıralanmış olarak döndürür (işaretsiz olarak karşılaştırılır, bu yüzden negatif üyeler en sona gelir); Enum.GetNames adlarını döndürür. Bir açılır listeyi doldurmanın ya da her seçeneğe karşı doğrulamanın yolu budur:

Çıktı:

Free       0 EUR/month
Starter    9 EUR/month
Pro       29 EUR/month
Team      99 EUR/month
Free | Starter | Pro | Team
3 paid plans

Enum.GetValues(typeof(Plan)) düz bir Array döndürür; LINQ'ten önceki Cast<Plan>() bu yüzdendir. .NET 5 ve sonrasında Enum.GetValues<Plan>() doğrudan tipli bir Plan[] döndürür.

Flags: değerleri birleştirmek

Bazı enum'lar tek bir seçim yerine bir seçenekler kümesini tanımlar: dosya izinleri, bir dükkânın açık olduğu günler, bildirim kanalları. Her üyeye kendi bitini (1, 2, 4, 8, ...) verin, None = 0 ekleyin ve enum'u [Flags] ile işaretleyin. Değerler bundan sonra | ile birleşir:

Çıktı:

Read, Share
Editor, Share
True
False
Editor
3
Read, Delete
True

Her operatörün yaptığı: | bitleri ayarlar, & ~X onları temizler, ^ onları tersine çevirir ve (value & X) != 0 ya da value.HasFlag(X) onları test eder. HasFlag(X) "X'in tüm bitleri ayarlı" demektir, bu yüzden HasFlag(None) her değer için true'dur ve HasFlag(Editor) hem Read hem de Write gerektirir.

İkinci satıra dikkat edin: adlandırılmış bir kombinasyon ayarlı bitlerin bir kısmını kapsadığında ToString onu kullanır, bu yüzden Read | Write | Share Editor, Share olarak yazdırılır. ToString'in çıktısını Enum.Parse dışında bir şeyle parse etmeden önce bunu aklınızda tutun.

Öznitelik aritmetiği değiştirmez. Biçimlendirmeyi değiştirir: [Flags] olmadan Read | Share 9 olarak yazdırılır, çünkü hiçbir üyenin tek başına bu değeri yoktur. Onunla ToString ve Parse ikisi de virgülle ayrılmış biçimle çalışır. Üyeler yine de ikinin kuvvetleri olmalıdır; Read, Write, Delete'i varsayılan numaralandırmayla (0, 1, 2) yazmak Write | Delete'i anlamsız bir değer olan 3'e eşit yapar.

Bir enum üzerinde switch

switch, bir enum'a göre işlem yapmanın doğal yoludur. Bir default dalı ekleyin, çünkü bir enum değişkeni adı olmayan değerler tutabilir:

switch (status)
{
    case OrderStatus.Pending:
    case OrderStatus.Paid:
        return "Preparing";
    case OrderStatus.Shipped:
        return "On the way";
    case OrderStatus.Delivered:
        return "Delivered";
    default:
        return "Unknown";
}

C# 8'den beri bir switch expression daha kısadır. _ kolu olmadan derleyici uyarır: adlandırılmış bir üye eksikse CS8509, her ad ele alınmış ama (OrderStatus)7 gibi adsız değerler ele alınmamışsa CS8524:

string text = status switch
{
    OrderStatus.Pending or OrderStatus.Paid => "Preparing",   // 'or' pattern: C# 9
    OrderStatus.Shipped => "On the way",
    OrderStatus.Delivered => "Delivered",
    OrderStatus.Cancelled => "Cancelled",
    _ => throw new ArgumentOutOfRangeException(nameof(status)),
};

Varsayılan ve tanımsız değerler

Herhangi bir enum'un varsayılan değeri, bir üyenin o değere sahip olup olmadığına bakılmaksızın 0'dır. Alanlar, dizi elemanları ve başarısız bir TryParse hepsi onu üretir. Buna göre tasarlayın:

  • 0'ı gerçek bir seçim yerine anlamlı bir "ayarlanmadı" üyesi (None, Unknown) yapın. Aksi halde başlatılmamış bir alan sessizce ilk gerçek seçenek olarak okunur.
  • Dışarıdan gelen sayıları Enum.IsDefined ile doğrulayın. [Flags] enum'ları için IsDefined adı olmayan kombinasyonlar (Read | Share) için false döndürür, bu yüzden bunun yerine bitleri kontrol edin: her biti kapsayan bir All üyesiyle (value & ~Permissions.All) == 0.

Yaygın hatalar

  • Yalnızca TryParse'a güvenmek. Sayısal string'ler parse edilir ve başarısız bir parse 0 verir. Enum.IsDefined ekleyin.
  • Saklanan değerler için örtük numaralandırmaya güvenmek. Bir üye eklemek ondan sonrakileri yeniden numaralandırır. Kalıcı olarak saklanan her enum'a açık değerler atayın.
  • İkinin kuvveti olmayan flags. Varsayılan numaralandırma (0, 1, 2, 3) bitleri çakıştırır. 1, 2, 4, 8 ya da 1 << n kullanın.
  • Kullanıcılara ToString() göstermek. Üye adları kod tanımlayıcılarıdır. Değerleri gösterim metnine eşleyin.
  • Bir switch'te default olmaması. Bir enum adlandırılmış üyelerinin dışında değerler tutabilir.

Sıkça Sorulan Sorular

C#'ta bir enum string'e nasıl çevrilir?

ToString() çağırın: OrderStatus.Shipped.ToString() "Shipped" döndürür ve string interpolation aynısını yapar. ToString("D") bunun yerine sayıyı verir. Derleme zamanında bilinen bir ad için nameof(OrderStatus.Shipped) bir sabittir. Boşluklu ya da çevrilmiş kullanıcıya dönük metin için üye adına güvenmek yerine değerleri kendiniz string'lere eşleyin (bir switch ya da bir dictionary).

C#'ta bir string enum'a nasıl çevrilir?

Metin hiçbir üyeyle eşleşmediğinde istisna fırlatmak yerine false döndüren Enum.TryParse<OrderStatus>(text, true, out var status)'u kullanın (true harf duyarsız yapar). Enum.Parse(typeof(OrderStatus), text) hatalı girdide ArgumentException fırlatır. İkisi de "42" gibi sayısal string'leri de kabul eder, bu yüzden girdi kullanıcılardan geldiğinde sonucu Enum.IsDefined ile kontrol edin.

C#'ta enum ile int arasında nasıl dönüşüm yapılır?

İki yönde de cast edin: int code = (int)OrderStatus.Paid; ve var status = (OrderStatus)2;. int'ten cast, eşleşen üyesi olmayan sayılar için bile asla başarısız olmaz; sonuç sayı olarak yazdırılan bir enum değeridir. Sayı dışarıdan geldiğinde Enum.IsDefined(typeof(OrderStatus), value) ile doğrulayın.

C#'ta bir enum'un tüm değerleri üzerinde nasıl döngü kurulur?

foreach (OrderStatus s in Enum.GetValues(typeof(OrderStatus))) her üyeyi sayısal değerlerinin sırasıyla ziyaret eder. .NET 5'ten beri cast gerektirmeyen generic bir sürüm vardır: Enum.GetValues<OrderStatus>(). Enum.GetNames(typeof(OrderStatus)) adları string olarak döndürür.

C# enum'unda [Flags] ne işe yarar?

Değerleri, Read | Write gibi | ile birleştirilmek üzere tasarlanmış bitler olan bir enum'u işaretler. Her üyeye ikinin bir kuvvetini (1, 2, 4, 8) ve bir None = 0 verin. Öznitelik, ToString()'in kombinasyonları "Read, Write" olarak yazdırmasını ve Enum.Parse'ın bu biçimi geri okumasını sağlar. Bir biti HasFlag ya da (value & Permissions.Write) != 0 ile test edin.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA