الوصول بكفاءة إلى السمات المخصصة على قيم التعدادات في C#

إذا كنت تطور تطبيقات بلغة C#، فقد تصادف أحيانًا الحاجة إلى جلب السمات المخصصة المرتبطة بقيم التعداد. قد تبدو هذه المهمة بسيطة، خاصةً بالنسبة لأولئك الذين ليسوا على دراية بالانعكاس وتوليد رمز IL. ومع ذلك، يمكن أن يؤدي تحويل قيم التعداد إلى سلاسل نصية (أسمائها) غالبًا إلى مشاكل في الأداء. في هذا المنشور، سنستعرض طريقة نظيفة وفعّالة لاسترجاع هذه السمات دون عناء تحويل السلاسل النصية.

فهم المشكلة

دعونا نبدأ بمثال سريع حيث نعرف تعدادًا مزينًا بسمات مخصصة:

public enum MyEnum {
    [CustomInfo("هذه سمة مخصصة")]
    None = 0,

    [CustomInfo("هذه سمة أخرى")]
    ValueA,

    [CustomInfo("هذا لديه علامة إضافية", AllowSomething = true)]
    ValueB,
}

في هذا المقتطف، لدينا تعداد يسمى MyEnum يحتوي على عدة قيم، كل منها مرتبط مع سمة CustomInfo توضح معلومات إضافية تتعلق بكل عضو من أعضاء التعداد.

التحدي

التحدي الأساسي ينشأ عندما نحتاج إلى استرجاع سمات CustomInfo من مثيل التعداد. الطريقة الأولية التي تتبادر إلى الذهن هي استخدام الكود التالي:

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

بينما تقوم هذه الدالة باسترجاع السمة بفعالية، إلا أنها تعاني من كفائات أداء منخفضة بسبب استخدام enumInput.ToString()، الذي يحول قيمة التعداد إلى تمثيل نصي.

نهج أفضل: استخدام توليد رمز IL

لحسن الحظ، هناك طريقة أكثر كفاءة للوصول إلى السمات المخصصة دون تحويل التعدادات إلى سلاسل نصية باستخدام توليد رمز IL. من خلال استخدام الطرق الديناميكية وILGenerator، نقلل من الأعباء ونحسن الأداء. أدناه، نستعرض كيفية إنشاء مفوض يساعد في الوصول إلى الخصائص بسرعة، والذي يمكن تعديله لاسترجاع السمات أيضًا.

خطوات تنفيذ توليد رمز IL

  1. إنشاء مفوض: تعريف مفوض يأخذ كائنًا ويعيد كائنًا. سيمكننا ذلك من إنشاء طريقة جلب خصائص سريعة.

    public delegate object FastPropertyGetHandler(object target);
    
  2. إصدار IL: باستخدام ILGenerator، يمكننا توليد دالة IL التي تقوم بتحميل كائن الهدف على المكدس، وتستدعي دالة الجلب، وتعالج قيمة الإرجاع بشكل صحيح.

    private static void EmitBoxIfNeeded(ILGenerator ilGenerator, System.Type type) {
        if (type.IsValueType) {
            ilGenerator.Emit(OpCodes.Box, type);
        }
    }
    
  3. الحصول على جالب الخاصية: الآن، نقوم بإنشاء دالة لتوليد دالة ديناميكية وبناء شفرة IL اللازمة لإنشاء جالب خاصية سريع:

    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;
    }
    

الخاتمة

من خلال تنفيذ الطريقة الموضحة أعلاه، يمكنك تقليل الأعباء المرتبطة باسترجاع السمات من قيم التعداد بشكل فعال. لا تقضي هذه الطريقة على تحويلات السلاسل النصية غير الضرورية فحسب، بل تسهم أيضًا في تحسين أداء وقت التشغيل - وهو أمر أساسي للتطبيقات التي تتطلب الكفاءة.

سيساعدك دمج هذه التقنيات في مشاريع C# الخاصة بك في التنقل بسلاسة عبر سمات التعدادات ويسمح لك بكتابة كود أنظف وأكثر قابلية للصيانة. برمجة سعيدة!