On parle Windows, C#, Apple, Android, Js, …

Méthodes dynamiques (classe DynamicMethod) en .NET

Utiliser la réflexion pour invoquer des méthodes non connues à la compilation peut être problématique en terme de performances dans des applications critiques. L’exécution de ces méthodes est environ 2,5 à 3 fois plus lente qu’un appel directe.
Voici un exemple :

    class Program
    {
        [DllImport("kernel32.dll")]
        static extern void QueryPerformanceCounter(ref long ticks);

        static PropertyInfo _intProp = typeof(Foo).GetProperty("IntProp", BindingFlags.Public | BindingFlags.Instance);

        static void Main(string[] args)
        {
            Foo foo = new Foo { IntProp = 10 };
            const int COUNT = 1;
            Console.WriteLine(Measure(() => ReadPropertyWithReflection(foo), COUNT));
            Console.WriteLine(Measure(() => ReadPropertyDirectly(foo), COUNT));
        }

        static void ReadPropertyWithReflection(Foo foo)
        {
            int intProp = (int)_intProp.GetValue(foo, null);
        }

        static void ReadPropertyDirectly(Foo foo)
        {
            int intProp = foo.IntProp;
        }

        static long Measure(Action action, int count)
        {
            long startTicks = 0;
            QueryPerformanceCounter(ref startTicks);
            for (int i = 0; i < count; i++)
            {
                action();
            }
            long endTicks = 0;
            QueryPerformanceCounter(ref endTicks);
            return endTicks - startTicks;
        }

        class Foo
        {
            public int IntProp { get; set; }
        }
    }

Et voici les résultats :

Type d’accès unités CPU
Invocation par accès directe 796
Invocation par Réflexion 1986

Ainsi, l’utilisation de la réflexion pour lire une propriété est 2,5 fois plus lente que l’accès directe à cette propriété.

Les méthodes dynamiques peuvent être utilisées pour générer et exécuter une méthode à l’exécution sans devoir déclarer une assemblie dynamique et un type dynamique qui contiendront la méthode. Elles représentent un moyen plus efficace pour générer et exécuter ce type de code.


Voici un exemple d’utilisation de la classe de méthode dynamique (DynamicMethod) pour générer un accès en lecture à la propriété.

    static Func<Arg0, TReturn> EmitGetter<Arg0, TReturn>(PropertyInfo propertyInfo)
    {
        MethodInfo mi = propertyInfo.GetGetMethod();
        DynamicMethod dm = new DynamicMethod(
            "_get",
            typeof(TReturn),
            new Type[] { typeof(Arg0) },
            propertyInfo.DeclaringType);

        ILGenerator il = dm.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
        il.EmitCall(OpCodes.Callvirt, mi, null);
        il.Emit(OpCodes.Ret);

        return (Func<Arg0, TReturn>)dm.CreateDelegate(typeof(Func<Arg0, TReturn>));
    }

Utilisons maintenant cette méthode pour définir un accès en lecture à PropertyInfo en exécution et retourner le délégué.

    Func<Foo, int> getter = EmitGetter<Foo, int>(_intProp);
    Console.WriteLine(Measure(() => getter(foo), COUNT));

Et voici les résultats obtenus avec les 3 type d’accès différents pour lire la valeur de la propriété :

Type d’accès unités CPU
Invocation par accès directe 796
Invocation avec Dynamic method 1190
Invocation par Réflexion 1986

Laissez un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.