C#’ta Enum Değerlerindeki Özel Niteliklere Etkili Erişim

C# ile uygulama geliştiriyorsanız, bazen enum değerleriyle ilişkili özel nitelikleri almak gerektiğini görebilirsiniz. Bu görev, yansıma ve IL kodu oluşturma ile ilgili temel bilgisi olmayanlar için oldukça basit görünebilir. Ancak, enum değerlerini string’lere (isimlerine) dönüştürmek genellikle performans sorunlarına yol açabilir. Bu blog yazısında, bu nitelikleri string dönüşümleriyle uğraşmadan almanın temiz ve verimli bir yolunu keşfedeceğiz.

Problemi Anlamak

Öncelikle, özel niteliklerle süslenmiş bir enum tanımlayarak hızlı bir örneğe bakalım:

public enum MyEnum {
    [CustomInfo("Bu bir özel atıf")]
    None = 0,

    [CustomInfo("Bu başka bir atıf")]
    ValueA,

    [CustomInfo("Bu ek bir bayrağa sahiptir", AllowSomething = true)]
    ValueB,
}

Bu kod parçasında, MyEnum adında bir enum tanımladık, bu enum birden fazla değer içeriyor ve her biri CustomInfo niteliği ile ilişkilendirilmiş ek bilgileri içeriyor.

Zorluk

Temel zorluk, enum’un bir örneğinden bu CustomInfo niteliklerini elde etme ihtiyacının ortaya çıkmasıdır. Aklımıza gelen ilk yöntem, aşağıdaki kodu kullanmaktır:

public CustomInfoAttribute GetInfo(MyEnum enumInput) {
    Type typeOfEnum = enumInput.GetType();
    FieldInfo fi = typeOfEnum.GetField(enumInput.ToString());
    return fi.GetCustomAttributes(typeof(CustomInfoAttribute), false).
        FirstOrDefault() as CustomInfoAttribute;
}

Bu fonksiyon niteliği etkili bir şekilde alırken, enumInput.ToString() kullanımı nedeniyle performans sorunu yaşamaktadır; bu, enum değerini string karşılığında dönüştürür.

Daha İyi Bir Yaklaşım: IL Kod Oluşturma Kullanımı

Neyse ki, enum’ları string’lere dönüştürmeden özel nitellikere erişmenin daha verimli bir yolu var: IL kodu oluşturma. Dinamik yöntemler ve ILGenerator kullanarak, yükü azaltabilir ve performansı artırabiliriz. Aşağıda, özelliklere hızlı bir şekilde erişim sağlamaya yardımcı olan bir delege yaratmanın adımlarını sıralıyoruz; bu yöntem, nitelik alımı için de uyarlanabilir.

IL Kodu Oluşturmayı Uygulama Adımları

  1. Bir Delege Oluşturun: Bir nesne alıp nesne döndüren bir delege tanımlayın. Bu, hızlı bir özellik alıcı oluşturma imkanı sağlar.

    public delegate object FastPropertyGetHandler(object target);
    
  2. IL Üretin: ILGenerator kullanarak, hedef nesneyi yığına yükleyen, alıcı yöntemini çağıran ve dönen değeri uygun bir şekilde işleyen bir IL yöntemi oluşturabiliriz.

    private static void EmitBoxIfNeeded(ILGenerator ilGenerator, System.Type type) {
        if (type.IsValueType) {
            ilGenerator.Emit(OpCodes.Box, type);
        }
    }
    
  3. Özellik Alıcısı Edinin: Şimdi, dinamik bir yöntem oluşturmak ve bir hızlı özellik alıcısı oluşturmak için gerekli IL kodunu oluşturacak bir metod yazalım:

    public static FastPropertyGetHandler GetPropertyGetter(PropertyInfo propInfo) {
        DynamicMethod dynamicMethod = new DynamicMethod(
            string.Empty, 
            typeof(object), 
            new Type[] { typeof(object) },
            propInfo.DeclaringType.Module);
    
        ILGenerator ilGenerator = dynamicMethod.GetILGenerator();
        ilGenerator.Emit(OpCodes.Ldarg_0);
        ilGenerator.EmitCall(OpCodes.Callvirt, propInfo.GetGetMethod(), null);
        EmitBoxIfNeeded(ilGenerator, propInfo.PropertyType);
        ilGenerator.Emit(OpCodes.Ret);
        FastPropertyGetHandler getter = (FastPropertyGetHandler)dynamicMethod.CreateDelegate(typeof(FastPropertyGetHandler));
        return getter;
    }
    

Sonuç

Yukarıda belirtilen yöntemi uygulayarak, enum değerlerinden nitelik alımı ile ilişkili yükü etkili bir şekilde azaltabilirsiniz. Bu yaklaşım sadece gereksiz string dönüşümlerini ortadan kaldırmakla kalmaz, aynı zamanda daha hızlı çalışma performansı sağlar—verimlilik gerektiren uygulamalar için bu hayati önem taşır.

Bu teknikleri C# projelerinize dahil etmek, enum niteliklerinde kolaylıkla dolaşmanıza yardımcı olacaktır ve daha temiz, sürdürülebilir bir kod yazmanızı sağlayacaktır. İyi kodlamalar!