İlkay İlknur

just a developer...

Çoklu Enum Değerleriyle Çalışmak

.NET Framework içerisindeki enumerationlarin yapisina baktigimizda eminim ki bir çogumuz her bir enum üyesinin tek bir deger tasidigini biliyoruzdur. Örnegin asagidaki gibi yetkileri temsil eden bir enumeration'imiz oldugunu düsünelim.

public enum Yetki
{
    Ekleme,
    Silme,
    Degistirme
}

Buraya kadar hersey yolunda :) Simdi diyelim ki bu enumerationi kullanarak yetkilerin atamasini yapan bir metot yazacagiz ve bu metot içerisinde ilgili kullaniciya birden fazla yetki atamasi yapilmasina da olanak saglayacagiz.

Bu istekleri ilk olarak düsündügümüzde aklimiza gelen en basit yöntem tabi ki metot parametresi olarak Yetki tipini tasiyan bir list veya array almak. Öyleyse bu sekilde bir implemantasyon yapalim.

class Program
{
    static void Main(string[] args)
    {
        var list = new List<Yetki>()         {             Yetki.Degistirme,             Yetki.Ekleme         };
        YetkiAta(list.ToArray());
    }

    static void YetkiAta(Yetki[] yetkiler)
    {
        Console.WriteLine("Verilen Yetkiler: " + yetkiler.ToString());
        foreach (Yetki yetki in yetkiler)
        {
            Console.WriteLine(yetki.ToString());
        }

    }
    public enum Yetki
    {
        Ekleme,
        Silme,
        Degistirme
    }
}

Koda baktigimizda aslinda her sey yolunda gibi. Kodu çalistirip bir de sonucu inceleyelim.

Çikan sonuca baktigimizda aslinda tek bir sey haricinde her sey yolunda gibi. Yolunda olmayan tek sey ise gelen yetkilerin tamamini dogru bir sekilde yazdiramamamiz.  Bunun yaninda bir de metot kullanimina baktigimizda metodu kullanan developerin elindeki yetkileri toplayarak bir list veya array olusturmasini saglayarak aslinda yazdigimiz metodun kullanimini biraz da olsa zorlastirmaktayiz. Ayrica ileride Admin veya modarator gibi içerisinde birden fazla yetkiyi barindiran üyeler tanimlamak istedigimizde bu üyelerin hangi yetkileri tasidigini mecburen YetkiAta metodu içerisine gömecegiz.

Peki baska çaremiz var mi ? :)

Flags Attribute

FlagsAttribute sinifi System namespace'i altinda bulunmakla beraber bizim tanimlamis oldugumuz enumerationlara çoklu degerler vermemizi saglamakta. Bunu da yaparken aslinda arka planda bit operasyonlarini kullanmakta. Peki Flags attribute'ünü nasil kullaniyoruz ? Hemen o konuya gelelim. Ilk olarak enumeration tanimimizin üzerine Flags attribute'ünü yerlestiriyoruz.

[Flags]
public enum Yetki
{
    Ekleme,
    Silme,
    Degistirme
}

Bir önceki paragrafi hatirlarsaniz flags attribute'ünü ekledigimizde artik enum valuelari üzerinde bit operasyonlari gerçeklestirebilecegimizden bahsetmistim. Iste bu bit operasyonlarindan dolayi enum valuelarina da 2'nin üstleri (1,2,4,8,16...) degerler vermeliyiz ki runtime arka planda bu operasyonlari kendisi handle edebilsin. Öyleyse Yetki enumini yukaridaki kurallara göre degistirelim.

[Flags]
public enum Yetki
{
    Ekleme = 1,
    Silme = 2,
    Degistirme = 4
}

Bunlari yaptiktan sonra peki metodumuz içerisindeki kullanim nasil olacak ? Hemen enumeration'in yeni durumuna göre kodu güncelleyelim.

class Program
{
    static void Main(string[] args)
    {
        YetkiAta(Yetki.Degistirme | Yetki.Ekleme);
    }

    static void YetkiAta(Yetki yetkiler)
    {
        Console.WriteLine("Verilen Yetkiler: " + yetkiler.ToString());

        if (yetkiler.HasFlag(Yetki.Ekleme))
        {
            Console.WriteLine("Ekleme yetkisi istendi");
        }
        if (yetkiler.HasFlag(Yetki.Silme))
        {
            Console.WriteLine("Silme yetkisi istendi");
        }
        if (yetkiler.HasFlag(Yetki.Degistirme))
        {
            Console.WriteLine("Degistirme yetkisi istendi");
        }
    }
}
[Flags]
public enum Yetki
{
    Ekleme = 1,
    Silme = 2,
    Degistirme = 4
}

Kodumuzun yeni haline baktigimizda aslinda bazi farkliliklar oldugunu farketmisinizdir. Bu degisikliklerden ilki YetkiAta metodu içerisindeki if kontrolleri. Her ne kadar ilk baktigimizda bu kontroller kötü dursa da bu noktada aslinda baska bir çaremiz yok gibi. Çünkü artik metot parametresine baktigimizda list veya array tipinde bir parametremiz yok. Sadece Yetki enumeration'i aliyoruz parametre olarak. Haliyle bu enumeration içerisinde birden fazla deger tasiyabildigi için kontrollerimizi HasFlag metoduyla yapiyoruz. HasFlag metodu eger elimizdeki enum degeri içerisinde, parametre olarak verdigimiz enum degerini barindiriyorsa bize true degerini dönüyor.

Simdi yazdigimiz kodu çalistiralim.

Ekran görüntüsünden de farkettiyseniz Flags attribute'ünü kullanmanin güzelliklerinden biri de ToString metodunun çagriminda artik çoklu enum degeri içerisindeki tüm enum degerlerinin virgülle ayrilarak yazilmasi. Bunun yaninda Flags attribute'ünü kullandigimizda Enum tipi içerisinde bulunan Parse metodu içerisinde çoklu enum isimlerini virgül ile ayirarak verdigimizde ilgili degerlerin otomatik olarak Enum'a atanmasi mümkün. Örnegin,

class Program
{
    static void Main(string[] args)
    {
        Yetki yetki = (Yetki)Enum.Parse(typeof(Yetki), "Silme,Ekleme");
        Console.WriteLine(yetki.ToString());
    }
}

[Flags]
public enum Yetki
{
    Ekleme = 1,
    Silme = 2,
    Degistirme = 4
}

Kodu çalistirdigimizda gördügünüz gibi enumerationa Silme,Ekleme otomatik olarak ataniyor ve ToString metoduyla otomatik olarak ekrana yaziliyor.

Son olarak bahsedecegim özellik ise enumlar içerisinde de Flags attribute'ü kullanarak birden fazla degeri içerisinde barindiran üyeler tanimlayabilmemiz. Örnegin yetkilere Admin ve Moderatör olarak 2 yeni kavram ekleyelim ve Admin'in tüm yetkileri olacagini, moderatörün ise sadece silme ve degistirme yapabilecegini düsünelim. Bunun için enumeration içerisinde yapmamiz gereken 2 yeni üye tanimlayip bu üyelere gerekli yetkileri vermek.

class Program
{
    static void Main(string[] args)
    {
        Yetki yetki = Yetki.Admin;
        YetkiAta(yetki);
    }

    static void YetkiAta(Yetki yetkiler)
    {
        Console.WriteLine("Verilen Yetkiler: " + yetkiler.ToString());

        if (yetkiler.HasFlag(Yetki.Ekleme))
        {
            Console.WriteLine("Ekleme yetkisi istendi");
        }
        if (yetkiler.HasFlag(Yetki.Silme))
        {
            Console.WriteLine("Silme yetkisi istendi");
        }
        if (yetkiler.HasFlag(Yetki.Degistirme))
        {
            Console.WriteLine("Degistirme yetkisi istendi");
        }
    }
}

[Flags]
public enum Yetki
{
    Ekleme = 1,
    Silme = 2,
    Degistirme = 4,
    Admin = Ekleme | Silme | Degistirme,
    Moderator = Silme | Degistirme
}

Yukarida gördügünüz gibi "Verilen Yetkiler" kisminda enum Admin olarak gelirken YetkiAta metodu içerisinde Enum.HasFlag metodunu kullanarak yaptigimiz yetki kontrollerinde Admin'in sahip oldugu esas yetkilere tek tek ulasabildik.

Evet bu yazimizda Flags attribute'ü ile ilgili olarak bahsedeceklerimiz bu kadar. Aslinda çok basit senaryolarda belki ilk olarak gördügümüz list veya array üzerinden ilerleyebiliriz. Ancak Flags attribute'ü ile beraber gelen esneklikler de gözardi edilecek seyler olmadigini düsünüyorum. Tabi yerine göre gelecek olan avantajlari ve yükleri dogru olarak öngörmemiz lazim.

Hosçakalin



Yorum Gönder


Yorumlar

  • profile

    Irmak

    • 23
    • 8
    • 2013

    teşekkürler, çok güzel bir anlatım.

  • profile

    burak

    • 12
    • 3
    • 2013

    Selamlar, Parse işlemi sırasında virgül notasyonu kullanımı ile sondaki Admin ve Moderator için yapılan atamalar oldukça etkileyici ve hoş kabiliyetler. Güzel yazıydı, teşekkürler.