C# Enumerated Tipler ve Bit Flag’lar

ismail kaşan
4 min readMay 30, 2023

--

C#’ta enum (sabit) ve bit flag, farklı amaçlara hizmet eden iki farklı özelliktir. C# ve birçok programlama dili bu yapıları uzun yıllardır kullandığından eminim ki herkes enum türlerini ve bit flagları nasıl kullanılacağına zaten aşinadır. Fakat, Common Language Runtime(CLR) ve Framewrok Class Library(FCL), enum türleri ve bit flag’ları için çoğu geliştiricinin aşina olmadığı harika özellikler sunmaktadır.

Enum (Sabit)

Enum, belirli bir veri türünde sınırlı sayıda değere sahip olan bir sabit listesini temsil eder. Enum, programcılara belirli bir değeri daha okunabilir ve anlaşılır bir şekilde temsil etme imkanı sağlar. Enumlar, genellikle bir dizi adlandırılmış sabit değeri temsil etmek için kullanılır.

Örneğin, renk durumunu temsil eden bir enum kullanabiliriz:

internal enum Color {
White, // Assigned a value of 0
Red, // Assigned a value of 1
Green, // Assigned a value of 2
Blue, // Assigned a value of 3
Orange // Assigned a value of 4
}

Bütün enum tipleri direkt olarak “System.Enum” tipinden miras alınır. “System.Enum” tipi de “System.ValueType” tipiden miras alınır. En sonunda “System.ValueType” tipi de “System.Object” tipinden miras alınır. Böylece, enum tipleri değer tipleridir ve boxed ve unboxed formları ile temsil edilebilirler. Fakat, Değer tipleri olamalarına rağmen, “methods”, “properties”, “events” gibi elemanları tanımlayamazlar. Metot eklemek için, “System.Enum” tipinin genişletilmesi gerekmektedir.

Enum tipler compile edildiğinde, C# compiler her sembolu constant bir field’e çevirir. Örneğin, “Color” enum tipini sanki aşağıdaki kod parçası gibi tanımlanmış olarak çevirir. Compiler zaten bu şekilde direk bir kod tanımlamanıza izin vermez. Bu sadece arka planda enum tipinin nasıl çevrildiğini göstermektedir.

internal struct Color : System.Enum {

// Below are public constants defining Color's symbols and values
public const Color White = (Color) 0;
public const Color Red = (Color) 1;
public const Color Green = (Color) 2;
public const Color Blue = (Color) 3;
public const Color Orange = (Color) 4;

// Aşağıdaki public nesne elemanı enum'in değerini tutar
public Int32 value__;
}

Constant değerler direkt Metadata dosyasında tutulurlar ve Reflection ile erişilebilirler. Buda şunu gösteriyor ki bütün enum tiplerinin sembolleri ve değerleri runtime esnasında erişilir. Ve bir enum tipinin stirng olan sembol değerinin value değeri elde edilebilir. Bütün bu işlemleri yapabilen statik ve instance metotlar “System.Enum” base tipinde yer alır. Dolayısıyla reflection kullanımının karmaşıklığından kurtarır.

Örneğin: “System.Enum” tipi statik metot olan “GetUnderlyingType” metodunu ve “System.Type” tipi instance metodu olan “GetEnumUnderlyingType” metodunu barındırırlar. Bu metotlar enum tipinin core tipini geri getirmektedir.

public static Type GetUnderlyingType(Type enumType); // Defined in System.Enum
public Type GetEnumUnderlyingType(); // Defined in System.Type

Her enum’in değer olarak tuttuğu tip vardır. Bunlar; “byte”, “sbyte”, “short”, “ushort”, “int”(c#’ta varsayılan), “uint”, “long”, veya “ulong”. Bunlar C#’in primitive tipleridir ve .NET içinde FCL’de bulunan tiplerdir. C#’ta enum’lar temel olarak “int” tipini temel alarak tanımlanırlar. Fakat bütün bu primitive tiplerde verilebilir. Örneğin aşağıdaki örnekte “byte” tipini temel tip olarak verilen bir enum tanımı yapılmıştır.

internal enum Color : byte {
White,
Red,
Green,
Blue,
Orange
}

// "System.Byte" çıktısı görünecektir.
Console.WriteLine(Enum.GetUnderlyingType(typeof(Color)));

Enum tipler primitive oldukları için bütün bu operatörleri (==, !=, <, >, <=, >=, +, -, ^, &, |, ~, ++, and — ) desteklemektedir. Bütün bu operatöler “value__” field’i ile kullanılır.

Ayrıca, enum tiplerde “System.Enum” tipinden miras alınan “ToString()” metodu ile birden farklı string çıktıları alınabilir.

Color c = Color.Blue;
Console.WriteLine(c); // "Blue" (General format)
Console.WriteLine(c.ToString()); // "Blue" (General format)
Console.WriteLine(c.ToString("G")); // "Blue" (General format)
Console.WriteLine(c.ToString("D")); // "3" (Decimal format)
Console.WriteLine(c.ToString("X")); // "03" (Hex format)

Bir enum’in içindeki sembol isimlerinin listesini almak için “System.Enum” tipi içindeki statik “GetValues” metodu veya “System.Type” tipi içindeki “GetEnumValues” instance metodu kullanılır.

public static Array GetValues(Type enumType); // Defined in System.Enum
public Array GetEnumValues(); // Defined in System.Type
Color[] colors = (Color[]) Enum.GetValues(typeof(Color));
Console.WriteLine("Tanımlanan sembol sayısı: " + colors.Length);
Console.WriteLine("Değer\tSembol\n-----\t------");

foreach (Color c in colors) {
// Display each symbol in Decimal and General format.
Console.WriteLine("{0,5:D}\t{0:G}", c);
}

// Çıktı
Tanımlanan sembol sayısı: 5
Değer Sembol
----- ------
0 White
1 Red
2 Green
3 Blue
4 Orange

Bit Flags

Bit flag, bir enumun değerlerinin ikili bitler olarak temsil edildiği bir tekniktir. Bu teknik, bir enumun birden çok değeri aynı anda taşımasına ve bu değerlerin birleştirilerek kullanılmasına olanak tanır. Bit flag’ler, genellikle birbirine bağlı veya birleştirilebilen seçeneklerin ifade edildiği durumlarda kullanılır.

Bit flag’lerin kullanımı, “[Flags]” özniteliğiyle birlikte belirtilir.

[Flags] // The C# compiler allows either "Flags" or "FlagsAttribute".
internal enum Actions {
None = 0,
Read = 0x0001,
Write = 0x0002,
ReadWrite = Actions.Read | Actions.Write,
Delete = 0x0004,
Query = 0x0008,
Sync = 0x0010
}

Yukarıda enum kısmında anlatılan bütün metotlar bit flag’ler içinde kullanılabilir. Çünkü bit flagler’de enum tipleridir. Sadece bir sembole birden fazla değerden oluşan bir kombinasyon verilebiliyor. Yukarıdaki örnekte “ReadWrite” sembolu gibi. “Actions.Read” ile “Actions.Write” değerlerinden bir kombinasyon verilmiştir.

Actions actions = Actions.Read | Actions.Delete; // 0x0005
Console.WriteLine(actions.ToString()); // "Read, Delete"

Yukarıdaki örnekte “ToString()” metodu 0x0005'e karşılık gelen sembol bulmak için enum’in “[Flags]” attribütü var mı yok mu ona bakar. Eğer olmasaydı direkt “5” getirecekti. Fakat bu örnekte “[Flags]” attribütü olduğu için “Actions.Read” ve “Actions.Delete” in işaret ettiği semboller(Read, Delete) gelir.

Enum’lar ve Bit Flag’ların Arasındaki Farklar

  • Enum, belirli bir değeri daha okunabilir bir şekilde temsil etmek için kullanılırken, bit flag birden çok seçeneği bir araya getirip birleştirilmiş bir değer olarak temsil etmek için kullanılır.
  • Enum, tek bir değeri temsil ederken, bit flag birden çok değeri aynı anda taşıyabilir.
  • Enum değerleri sıralı olarak atanırken, bit flag değerlerinin değerleri ikili olarak birleştirilir ve temsil edilir.
  • Enum değerleri varsayılan olarak sabit (constant) olarak kabul edilirken, bit flag değerleri | (bitwise OR) ve & (bitwise AND) gibi operatörlerle birleştirilebilir ve işlemler yapılabilir.

Özet olarak, enumlar sınırlı sayıda sabit değeri temsil ederken, bit flag’ler birden çok değeri birleştirebilme yeteneğine sahiptir. Enumlar daha okunabilir bir şekilde sabit değerlerin temsil edilmesi için kullanılırken, bit flag’ler seçeneklerin bir araya getirilip işlemler yapılabilmesi için kullanılır.

Yararlanılan kaynaklar:

Microsoft CLR via C# Fourth Edition kitabı.

Tutorials Teacher

--

--

ismail kaşan
ismail kaşan

Written by ismail kaşan

I am a full stack developer since 2016.

No responses yet