IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Func, Expression et CSharpCodeProvider


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    110
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 110
    Par défaut Func, Expression et CSharpCodeProvider
    Bonjour à tous,

    Je suis en train de réaliser un moteur de règle pour les besoins d'un projet et je rencontre 2 soucis.

    1)Le premier est la création de règle, celles-ci sont stockées dans une base de données SQL puis récupérer dans un service windows (au démarrage et lors de la modification d'une des règles via le back office).
    Les règles sont de la forme :
    Name Operator Target
    Nom NotEqual toto
    Code.Length Equal 5
    DateNaissance GreaterThan 01/01/1900

    Name, Code et DateNaissance correspondent aux attributs de ma classe.

    Afin de créer mes règles côtés C# voilà les 2 procédures que j'utilise :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    public static Func<T, bool> CompileRule<T>(Rule r)
    {
        var paramUser = Expression.Parameter(typeof(T));            
        Expression expr = BuildExpr<T>(r, paramUser);            
        return Expression.Lambda<Func<T, bool>>(expr, paramUser).Compile();
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    static Expression BuildExpr<T>(Rule r, ParameterExpression param)
    {
     
        var left = MemberExpression.Property(param, r.MemberName);           
        var tProp = typeof(T).GetProperty(r.MemberName).PropertyType;
        ExpressionType tBinary;            
        if (ExpressionType.TryParse(r.Operator, out tBinary))
        {
            var right = Expression.Constant(Convert.ChangeType(r.TargetValue, tProp)); 
            return Expression.MakeBinary(tBinary, left, right);
        }
        else
        {
            var method = tProp.GetMethod(r.Operator);
            var tParam = method.GetParameters()[0].ParameterType;
            var right = Expression.Constant(Convert.ChangeType(r.TargetValue, tParam));
            return Expression.Call(left, method, right);
        }
    }
    Lorsque je viens pour créer mes règles 1 et 3, pas de soucis cela fonctionne mais pour la règle 2 il y a une erreur qui dit que Code.Length n'est pas un membre de ma classe. Cela est normal car Length est une propriété de la classe string pour retourner la longueur de la chaîne. J'ai regardé sur le net pour pouvoir retourner les propriétés imbriqués pour une classe mais je ne trouve pas de solution. L'erreur se produit dans la 2ème procédure sur la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    var left = MemberExpression.Property(param, r.MemberName);
    Pour le moment j'ai contourné le problème en ajoutant un attribut Code_Length dans ma classe, mais cela n'est pas propre si je dois créer un attribut pour chaque propriété. De plus, mes classes sont créer dynamiquement via la classe CSharpCodeProvider afin de pouvoir les recompiler en cas de modification depuis le back office.

    2) Le second problème vient justement de la gestion dynamique de mes classes pour créer mes règles. La fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Func<T, bool> CompileRule<T>(Rule r)
    attendant un type T qui correspond à une classe or je ne peux pas le préciser physiquement puisque je gère plusieurs classes en mémoire.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Func<Personne, bool> compiledRule = CompileRule<Personne>(rule);
    Mes classes sont créer comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    CSharpCodeProvider cl = new CSharpCodeProvider();
    var cp = new CompilerParameters();
    cp.GenerateInMemory = true;
     
    var res = cl.CompileAssemblyFromSource(
                    cp,
                    "using System; public class Personne \t{ public string Nom {get; set;} public string Code {get; set;} public DateTime DateNaissance {get; set;} public string Hello() { return \"Bonjour \" + Nom + \" !\"; } }"
                );
     
    var type = res.CompiledAssembly.GetType("Personne");
    var obj = Activator.CreateInstance(type);
    La seule solution que je vois, serait de gérer dynamiquement dans une classe statique, autant de "Func" que j'ai de classe mais cela va vite devenir compliquer si tout est dynamique.
    La solution n'est pas définitive si quelqu'un m'en propose une meilleure.

  2. #2
    Membre émérite Avatar de worm83
    Homme Profil pro
    Architecte logiciel
    Inscrit en
    Février 2010
    Messages
    459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte logiciel
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2010
    Messages : 459
    Par défaut
    Bonjour,

    La solution que j'avais utilisé (de mémoire) est de passer par une classe proxy qui contient une propriété T (ou object je me souviens plus) qui est la classe que tu désire, tes règles dérive de cette classe et override cette propriété (qui est le vrai type attendu, personne dans ton cas) et tu récupère cette instance.

    J'ai un exemple de code à la maison, je peux regarder ce soir si tu ne comprend pas ce que j'essaye de t'expliquer.

  3. #3
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    110
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 110
    Par défaut
    Je veux bien un exemple si tu as, même si je pense avoir compris le principe.

  4. #4
    Membre émérite Avatar de worm83
    Homme Profil pro
    Architecte logiciel
    Inscrit en
    Février 2010
    Messages
    459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte logiciel
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2010
    Messages : 459
    Par défaut
    Ok en rentrant ce soir je t envois un truc.

  5. #5
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    110
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 110
    Par défaut
    Ca marche merci

  6. #6
    Membre émérite Avatar de worm83
    Homme Profil pro
    Architecte logiciel
    Inscrit en
    Février 2010
    Messages
    459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte logiciel
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2010
    Messages : 459
    Par défaut
    Bonsoir,

    Alors en regardant mieux ce que tu as fait, je constate qu'il faut que tu renseigne le type que tu utilise, il te soit manque une colonne "type", soit déterminer le type par rapport à un pattern, par exemple quand ça commence par date tu sait que c'est une date, ou si le nom commence par toto tu sait que c'est une classe Toto, ou tu essaye de caster les valeur jusqu’à ce que ça "match" et correspond au type attendu. Il y a pleins de solutions possible mais à un moment il faut que détermine ce que tu va utiliser.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 5
    Dernier message: 14/04/2011, 13h57
  2. [expression régulière] mon cerveau fait des noeuds..
    Par nawac dans le forum Algorithmes et structures de données
    Réponses: 7
    Dernier message: 27/05/2003, 10h06
  3. [langage] expression reguliere motif répétitif dans 1 pattern
    Par comme de bien entendu dans le forum Langage
    Réponses: 11
    Dernier message: 09/04/2003, 16h14
  4. Expressions réguliéres
    Par Tooms dans le forum Langage
    Réponses: 4
    Dernier message: 06/12/2002, 18h42
  5. Réponses: 5
    Dernier message: 11/06/2002, 15h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo