.Net 5.0 İle Enum İşlemler
Selamlar,
Bu makalede, kodlarda bolca kullandığımız Enumlara, biraz daha detaylı inceleyeceğiz. Kod okunaklığının artması ya da bir başka deyişle 1,2,3 gibi anlamsız sayıların yerine anlamalı kelimelerin kullanılması, Enumların esas amacıdır. Peki bu enumlarda kullanılan kelimeleri boşluklu ve türkçe karakterler ile kullanmak istersek. Ya da işi daha da ileriye götürüp, bu Enumlardaki elemanları bir komboda listelemek ister isek ne yapmalıyız ?
Genelde bu gibi sorunlardan dolay gördüğüm en yanlış çözüm, aşağıdaki gibi static bir list’in, <key> ve <value> propertyleri olan bir model ile doldurulması olmuştur. Böylece ilgili liste içinde hem türkçe karakter bulundurulabiliyor, hem de istenen ComboBox’a datasource olarak gösterilebiliyordu. Aşağıdaki sınıfta static propertyler Enum gibi kullanılmak amacı ile, ilgili liste de ComboBox doldurmak amacı ile tanımlanmıştır. Tabi ki bütün bu tanımlamalara gerek yoktur. Zira sayısal, örneğin “2” şeklinde gelen bir SalesPriceType değerinin value karşılığını bulmak, ilgili liste içinden büyük bir performans kaybına neden olacaktır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
namespace StockList { public class EnumModel { public int value { get; set; } public string label { get; set; } } public static class SalesPriceType { public const int _NakitPrkFiyat = 1; ///<summary>2-2Prk Fiyati</summary> public const int _2PrkFiyati = 2; ///<summary>3-Nakit ToptFiyati</summary> public const int _NakitToptFiyati = 3; ///<summary>4-1Satis Fiyati</summary> public const int _1SatisFiyati = 4; ///<summary>5-2Satis Fiyati</summary> public const int _2SatisFiyati = 5; ///<summary>6-3Satis Fiyati</summary> public const int _3SatisFiyati = 6; ///<summary>7-4Satis Fiyati</summary> public const int _4SatisFiyati = 7; public static List<EnumModel> Items() { var list = new List<EnumModel> { new EnumModel { value = 1, label = "Nakit Prk.Fiyat" }, new EnumModel { value = 2, label = "2.Prk. Fiyatı" }, new EnumModel { value = 3, label = "Nakit Topt.Fiyatı" }, new EnumModel { value = 4, label = "1.Satış Fiyatı" }, new EnumModel { value = 5, label = "2.Satış Fiyatı" }, new EnumModel { value = 6, label = "3.Satış Fiyatı" }, new EnumModel { value = 7, label = "4.Satış Fiyatı" }, }; return list; } } } } |
Örnek Kullanım şekli:
1 |
if (result.SalesType == StockList.SalesPriceType._NakitPrkFiyat) |
“İnsanlar seni yanlış anladığında dert etme, duydukları senin sesin, fakat aklından geçirdikleri kendi düşünceleridir.”
―Mevlana
Enum Çözümü:
Öncelikle Enum’da türkçe karakter ve boşluk sorununu “[Display]” DataAnnotation’ı ile çözebiliriz.
SalesPriceType: Aşağıdaki Enum’da kullanılmak istenen tüm Açıklamalar, “Display” attribute’ü ile tanımlanmıştır. Görüldüğü gibi içinde, hem türkçe karakter hem de boşluk mevcuttur.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
enum SalesPriceType : byte { [Display(Name = "Nakit Prk.Fiyat")] NakitPrkFiyat = 1, [Display(Name = "2.Prk. Fiyatı")] PrkFiyatı = 2, [Display(Name = "Nakit Topt.Fiyatı")] NakitToptFiyatı = 3, [Display(Name = "1.Satış Fiyatı")] BirinciSatışFiyatı = 4, [Display(Name = "2.Satış Fiyatı")] İkinciSatışFiyatı = 5, [Display(Name = "3.Satış Fiyatı")] ÜcüncüSatışFiyatı = 6, [Display(Name = "4.Satış Fiyatı")] DördüncüSatışFiyatı = 7 } |
Örnek Kullanım Şekli:
Bir Liste olarak, seçilen bir comboya doldurulucak olan Enum model aşağıdaki gibidir:
1 2 3 4 5 |
public class EnumModel { public int Value { get; set; } public string Name { get; set; } } |
Gelin şimdi Enum üstündeki [DisplayAttribute] değerini veren, bir Extension yazalım.
1-) GetDisplayAttribute(): Aşağıdaki method, öncelikle kendisine gelen nesnenin, Enum olup olmadığına bakar. Daha sonra eğer Enum ise, “DisplayAttribute” field’ı var ise geri dönülür yok ise null dönülür. Aşağıdaki kodda akla gelebilecek tek sıkıntı, “GetCustomAttribute()” methodunun System.Reflection kütüphanesinden gelmesi ve bunun da performans üzerinde biraz da olsa etkisinin olmasıdır.
1 2 3 4 5 6 7 8 9 10 11 12 |
private static DisplayAttribute GetDisplayAttribute(object value) { Type type = value.GetType(); if (!type.IsEnum) { throw new ArgumentException(string.Format("Type {0} is not an enum", type)); } // Enum alanı geri dönülür. var field = type.GetField(value.ToString()); return field == null ? null : field.GetCustomAttribute<DisplayAttribute>(); } |
Extension
2-)EnumExtensions/GetDisplayName(): Aşağıda, Enum’a yazılan GetDisplayName extension’ını görüyoruz. Yukarıda tanımlanan “GetDisplayAttribute()”, methodu ile ilgili çekilen DisplayAttribute‘nun değeri geri dönülür.
1 2 3 4 5 6 7 8 |
public static class EnumExtensions { public static string GetDisplayName(this Enum enu) { var attr = GetDisplayAttribute(enu); return attr != null ? attr.Name : enu.ToString(); } } |
Örnek Kullanım Şekilleri:
- Örnekde, “NakitToptFiyatı” enum değerinin “[Display(Name)]” attribute’ü Console’a basılmıştır.
- Örnekde, “2” değerine karşılık gelen SalesPriceType Enumunun “[Display(Name)]” attribute’ü Console’a basılmıştır.
1 2 |
Console.WriteLine(SalesPriceType.NakitToptFiyatı.GetDisplayName()); //1.Örnek Console.WriteLine(((SalesPriceType)2).GetDisplayName()); //2.Örnek |
3-) GetEnumList<T>() : Aşağıda görüldüğü gibi, <T> tipinde istenen bir Enumun DisplayName’i ve Value’su, KeyValuePair model şeklinde bir Liste olarak geri dönülmektedir.
1 2 3 4 5 6 7 8 9 |
public static List<KeyValuePair<string, byte>> GetEnumList<T>() { var list = new List<KeyValuePair<string, byte>>(); foreach (var e in Enum.GetValues(typeof(T))) { list.Add(new KeyValuePair<string, byte>(((Enum)e).GetDisplayName(), (byte)e)); } return list; } |
Örnek Kullanım Şekli:
Aşağıda görüldüğü gibi “SalesPriceType” enumunun, [Display(Name)] ve buna karşılık gelen [Value] değeri Console’a basılmaktadır. Bu şekilde Key-Value tanımlaması ile istenen bir combo, Türkçe ve boşluklu olarak kolaylık dolurulabilir.
1 2 3 4 |
foreach (KeyValuePair<string, byte> model in GetEnumList<SalesPriceType>()) { Console.WriteLine($"[DisplayName]:{model.Key} - [Value]:{model.Value}"); } |
“Sorunlar, onları yaratanların mantığı ile çözümlenemez.”
―Albert Einstein
Enum Flags ve Bitwise :
Aşağıdaki Enum liste bakıldığında, [Flags] şeklinde bir attribute görülmektedir. Ve value değerleri 2’nin katı şeklinde artmaktadır. Buradaki Flags keyword’ü, birden fazla enum değerinin bir değişkene atanabilmesine imkan vermektedir.
1 2 3 4 5 6 7 8 9 10 |
[Flags] public enum WeaponType : byte { Axe = 1, Arrow = 2, Pistol = 4, Stick = 8, Sword = 16, Rifle = 32 } |
Örnek bir değişkene birden fazla değerin atanması: Aşağıdaki örnekde boraAttacker’a hem “Axe” hem de “Rifle” değerleri atanmıştır.
1 2 |
WeaponType boraAttacker = WeaponType.Axe | WeaponType.Rifle; Console.WriteLine(boraAttacker); |
Aşağıdaki örnekde, “HasFlag()” methodu ile aranan Axe enumunun boraAttacker’ın içinde olup olmadığı sorgulanmış ve “True” değeri dönülmüştür.
1 |
Console.WriteLine(boraAttacker.HasFlag(WeaponType.Axe)); |
Aşağıdaki kodun sonucu 33‘dür. (Axe = 1) + (Rifle = 32) = 33 toplamlarının sonucudur. Çünkü ilgili değişkene, her iki enum değeri atanmıştır.
1 |
Console.WriteLine((int)boraAttacker); |
Gelin boraAttacker’ın içinde bulunan tüm enumları listeleyelim. Öncelikle yukarıda yazılan “GetEnumList<T>()” methodu ile, WeaponType’a ait tüm listeyi “key, value” şeklinde alıp listeleyelim. Daha sonra, herbir elemanı “HasFlag()” methodunu kullanarak boraAttacker’in içinde var mı diye kontrol edelim. Olan silahları console’a yazdıralım.
1 2 3 4 |
GetEnumList<WeaponType>().ForEach(weapon => { if (boraAttacker.HasFlag((WeaponType)weapon.Value)) { Console.WriteLine($"Bora's Weapon: { weapon.Key}"); } }); |
Ekran çıktısı: Aşağıda görüldüğü gibi, boraAttacker’a tanımlı tüm WeaponType enumları listelenmektedir.
Bu makalede, kodlarda bolca kullanılan Enumlara biraz daha detaylı baktık. Özellikle Bitwise ile çoklu atamların yapılması ve Enumların bir liste olarak kullanılıp comboların doldurulması, bize hem kodlarda büyük kolaylık sağlıyacak hem de gereksiz kod kalabalığından kurtulmamızı olanak sağlıyacaktır. Türkçe karakter sorunu ve combobox doldurmak için Enumlar yerine oluşturulan static listlerden, daha sonrasında linq ve çeşitli sorgular ile data çekilmesi performans ve memory management anlamında özellikle yüksek trafikde bize sorunlara neden olacaktır.
Geldik bir makalenin daha sonuna.
Yeni bir makalede görüşmek üzere hepinize hoşçakalın.
Source Code: https://gist.github.com/borakasmer/0f38dd4a3b2b52535544254038ff2a77
Source :
- https://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/
- https://www.extensionmethod.net/csharp/enum/generic-enum-to-list-t-converter
- https://www.codingame.com/playgrounds/2487/c—how-to-display-friendly-names-for-enumerations
- https://stackoverflow.com/questions/13099834/how-to-get-the-display-name-attribute-of-an-enum-member-via-mvc-razor-code
Daydalı oldu.
Teşekkürler.
Teşekkürler..
Ufak bir düzeltme: 2’nin katı değil kuvveti şeklinde artmaktadır.
Selam Cihan,
Öncelikle teşekkürler. 2’nin kuvvetleri kesinlikle daha doğru bir ifade.
Sadece 2 için 2si de aynı kapıya çıkıyor :)
2’ye özel olarak 2’nin katları aynı anda 2’nin kuvvetleri oluyor :)
Yani pratikte kullanış şekli, her zaman enson kaydın ID’sini bul ve 2 ile çarpıp bir sonraki item’ın ID’si olarak ata.
2*2 = 2^2
2*2*2=2^3
2*2*2*2=2^4