CodeS-SourceS
Rechercher un code, un tuto, une réponse

Programmation dynamique dans le .Net

Juin 2017


Programmation dynamique



Introduction


Courte présentation (une petite approche) des techniques qui permettent la programmation dynamique : réflexion, génériques, arborescence d'expression, LINQ, création d'IL, compilation dynamique, DLR.
Bonne lecture...

La programmation dynamique

Par réflexion


Pour rappel : vous pouvez retourner le type (System.Type) d'un objet avec sa méthode GetType() (héritage de object) et d'un type avec le mot clef typeof. Partant de là, il est possible de connaître toutes les composantes de l'objet et de son type et d'utiliser ses méthodes -hors discussion sur les permissions-. Il existe d'autres mots clefs (is, as) et classes pour compléter l'utilisation. On peut ainsi `parcourir' et utiliser tout son module...


Exemple : utilisation d'une méthode connue d'une classe 'inconnue' contenant cette méthode

public void Add<T1, T2>(T1 liste, T2 item) {
    liste.GetType().GetMethod("Add").Invoke(liste, new object[] { item });
}

Avec le type dynamic (C#4)


C'est un nouveau type du prochain Framework 4 permettant de passer la compilation sans vérification (donc pas d'IntelliSense). Le type réel sera défini et vérifié dynamiquement par réflexion
Ex : dynamic objet = ..un objet, par exemple un List<string>..; objet.Add("string1");

De même, avec ScriptObject. Ex : ScriptObject liste = ..un objet, par exemple un List<string>..; liste.Invoke("Add", "string1");

Par utilisation d'un DynamicProxy


Il simule dynamiquement un objet (pouvant être distant) en interceptant les appels sur cet objet. Pour l'utiliser il faut dériver de la classe RealProxy (classe abstract de System.Runtime.Remoting.Proxies) et implémenter la méthode Invoke qui sera appelée pour chaque appel sur l'objet derrière le proxy.

Avec les génériques


Les délégués génériques :
- Func<..TypesParamètres.., TypeDeRetour> eq. à delegate TypeDeRetour Func(..TypesParamètres..);

- Action<..TypesParamètres..> eq. à delegate void Func(..TypesParamètres..);

Les classes génériques, ex :
public void CréationListGen<T>(T objet) {
    var typeListeGen = typeof(List<>);

    // Le CLR va définir dynamiquement le type générique (ex string). Equivaut ici à List<T>
    var typeListeDeStrings = typeListeGen.MakeGenericType(typeof(T));

    // Création d'une liste, juste pour l'exemple
    var listeDeStrings = typeListeDeStrings.GetConstructor(Type.EmptyTypes).Invoke(null);

    // Ajout d'un élément, juste pour l'exemple
    listeDeStrings.GetType().GetMethod("Add").Invoke(listeDeStrings, new object[] { objet });
}

Les arbres d'expressions


La classe Expression contient des méthodes de fabrique statiques qui créent des noeuds d'arborescence d'expression. L'espace de noms System.Linq.Expressions fournit une API pour générer des arborescences d'expression manuellement. On peut également fournir un délégué qui sera -si possible- décomposé en arbre. Cet arbre peut être parcouru, modifié et compilé dynamiquement. Ex :

// Expression lambda décomposée sous forme d'arbre.
Expression<Func<double, double>> expr = x => Math.Pow(x, 2) + 3 * x + 5;

// L'arbre est compilé en code qui pourra être exécuté par appel de delExpr.
Func<double, double> delExpr = expr.Compile();
double val = delExpr(5.0);

Avec LINQ


En effet les requêtes (notamment avec Linq to SQL) sont repoussées et exécutées uniquement au moment de leur utilisation. Pour ce faire Linq utilise abondamment les génériques, les expressions lambda et les arborescences d'expression.

Note : on peut - pour améliorer les performances - compiler ses requêtes. Ex :
System.Data.Linq.CompiledQuery.Compile((source, type de paramètres optionnels) => requête linq);

Par création et exécution dynamique de code par construction en IL


Dans System.Reflection.Emit plusieurs classes (DynamicMethod, etc) permettent de construire du code IL (Intermediate Language) qui peut être interprété dynamiquement.

Ex :
// Type des paramètres
Type[] helloArgs = { typeof(string), typeof(int) };

// Méthode crée dynamiquement
DynamicMethod hello = new DynamicMethod("Hello", // son nom
                                        typeof(int), // type du retour
                                        helloArgs, // type des paramètres
                                        typeof(string).Module);

// On prépare l'injection du code : sortie sur la Console...
Type[] writeStringArgs = { typeof(string) };
MethodInfo writeString = typeof(Console).GetMethod("WriteLine", writeStringArgs);
ILGenerator il = hello.GetILGenerator(256); // Injection du code...
il.Emit(OpCodes.Ldarg_0);
il.EmitCall(OpCodes.Call, writeString, null);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ret);

// Infos sur les paramètres ; pour le debugging
ParameterBuilder parameter1 = hello.DefineParameter(1, ParameterAttributes.In, "message");
ParameterBuilder parameter2 = hello.DefineParameter(2, ParameterAttributes.In, "valueToReturn");

// Un delegate pour exécuter la méthode dynamique.
HelloDelegate hi = (HelloDelegate)hello.CreateDelegate(typeof(HelloDelegate)); // avec delegate int HelloDelegate(string msg, int ret);
int retval = hi("rnHello, World!", 42);

Par envoi d'instruction sous forme de string au compilateur


Les classes dans l'espace Microsoft.CSharp (et System.CodeDom.Compiler) permettent de compiler (en mémoire ou dans un fichier) et le cas échéant d'exécuter du code contenu dans un string.

Ex :
CSharpCodeProvider provider = new CSharpCodeProvider();

ICodeCompiler compileur = provider.CreateCompiler();

CompilerResults cr = provider.CompileAssemblyFromSource(new CompilerParameters(), @"using System; public class Eval{public static double MultPar2(double x) { return x * 2; } }");// Le code.

if (cr.Errors.Count > 0) throw new Exception("Erreur sur le code dynamique.");

var ret = cr.CompiledAssembly.GetType("Eval").GetMethod("MultPar2").Invoke(null, new object[] { 50 });// Retourne 100.

Par utilisation des langages dynamiques (avec la DLR)


La Dynamic Language Runtime est une surcouche du .NET Framework 3.5 permettant de faciliter la création de langages dynamiques pour .NET. Ce langage peut être un langage intégré à une application ou plus largement l'implémentation d'un nouveau langage pour .NET à l'image d'IronPython ou de IronRuby. Son utilisation est facilitée avec Silverlight notamment avec le Javascript et/ou Python.

Ressources


Source en vidéo : http://www.microsoft.com/france/vision/mstechdays09/Webcast.aspx?eID=490a4112-6a60-403d-9e86-9ada349529b1

A voir également

Publié par TheManu.
Ce document intitulé «  Programmation dynamique dans le .Net  » issu de CodeS-SourceS (codes-sources.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.
Programmation parallèle et multi-coeur avec .NET
WPF : 10 bonnes raisons de choisir cette technologie