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 :

Fichier de script


Sujet :

C#

  1. #1
    Membre averti
    Inscrit en
    Juillet 2006
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : Juillet 2006
    Messages : 33
    Par défaut Fichier de script
    Bonjour,

    Dans le cadre d'un développement je dois rendre un programme encore plus flexible en permettant aux utilisateurs de scripter certains aspects du programme.

    Je m'explique ; j'ai un fichier contenant un nombre n de gammes, pour chacune de ces gammes je dois afficher des infos connues du programme ou aller en chercher dans des bases de données.
    J'avais d'abord créé mon propre langage de script qui marchait pour 95% des cas. Les 5 derniers pourcents étant vraiment dur à coder j'ai abandonné l'idée...

    Voila un exemple de la méthode que j'utilisais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    <Gamme cd="POLT" text="Dalle : _NUM_DALLE" />
    <Gamme cd="POLX" text="Outil : _OUTIL_" />
    Quelle est d'après vous la meilleure solution ?
    Faut il utiliser un langage de script ?

  2. #2
    Expert confirmé

    Avatar de Philippe Vialatte
    Homme Profil pro
    Architecte technique
    Inscrit en
    Juillet 2004
    Messages
    3 029
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juillet 2004
    Messages : 3 029
    Par défaut
    Bonjour,

    Qu'est-ce que tu entends par "scripter certains aspects du programme" ?

    Est-ce que stocker ce type d'info dans un fichier xml et lire ce meme fichier xml avec ton programme ne suffit pas ?

    Dasn ton exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    <Gamme cd="POLT" text="Dalle : _NUM_DALLE" />
    <Gamme cd="POLX" text="Outil : _OUTIL_" />
    Quelle est l'influence de ton fichier sur l'execution de ton programme ?
    Quelle est la complexite des actions scriptees ?
    Quel est le niveau attendu de tes utilisateurs ?

    Mon Blog

    The Cake is still a lie !!!



    Vous voulez contribuer à la rubrique .NET ? Contactez-moi par MP.
    Vous voulez rédiger des articles pour la rubrique .NET ? Voici la procédure à suivre.

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    tu peux utiliser la compilation dynamique, avec le namespace System.CodeDomProvider

  4. #4
    Membre averti
    Inscrit en
    Juillet 2006
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : Juillet 2006
    Messages : 33
    Par défaut
    @pvialatte

    Le programme interprète le fichier XML et doit remplacer des balises par des valeurs. Les exemples que j'ai donné sont assez simples.
    Les problèmes arrivent lorsque l'utilisateur veut afficher des valeurs que le programme ne connait pas forcément et qu'il doit récupérer d'une requête SQL que l'utilisateur met entre balises _REQUETE_ par exemple.
    C'est ça que j'appelle scripter.

    @tomlev

    Je suis pas sur d'avoir saisi à quoi ça sert. Il s'agit d'utiliser du code (C# par exemple) non compilé présent dans un autre fichier lors de l'exécution de mon programme?

  5. #5
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par Felloweis Voir le message
    @tomlev

    Je suis pas sur d'avoir saisi à quoi ça sert. Il s'agit d'utiliser du code (C# par exemple) non compilé présent dans un autre fichier lors de l'exécution de mon programme?
    voilà
    donc l'utilisateur peut écrire son propre script en C#, qui sera exécuté par le programme

  6. #6
    Membre averti
    Inscrit en
    Juillet 2006
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : Juillet 2006
    Messages : 33
    Par défaut
    Ah bah ça a l'air pas mal. Y'a possibilité d'utiliser VB pour ces scripts?

  7. #7
    Expert confirmé
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Par défaut
    Citation Envoyé par Felloweis Voir le message
    Ah bah ça a l'air pas mal. Y'a possibilité d'utiliser VB pour ces scripts?
    Oui on peut, par défaut le framework inclut les compilateurs pour le C# et le VB et il est possible de compiler dynamiquement le code vers une assembly avec le CodeDOM.
    Il y a un article qui en parle à cette addresse : http://vincentlaine.developpez.com/tuto/dotnet/codedom/

  8. #8
    Membre averti
    Inscrit en
    Juillet 2006
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : Juillet 2006
    Messages : 33
    Par défaut
    Je vais tester ça.

    Merci à tous !

  9. #9
    Membre averti
    Inscrit en
    Juillet 2006
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : Juillet 2006
    Messages : 33
    Par défaut
    Après mettre confronté au sujet j'ai une petite question... Peut on depuis ce code généré dynamique accéder aux classes de notre projet ?

    Le but étant d'executer une méthode présente dans une autre classe. Je souhaiterais donc passer l'objet de ladite classe en référence à ma fonction générée dynamiquement, puis à partir de ce code, executer ma fonction.

    Merci,

  10. #10
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    En général quand on propose des possibilités de scripting, on crée une interface, implémentée par l'application, via laquelle le script pourra accéder aux données publiées par l'application. Quand tu initialises la classe qui correspond au script, tu lui passes une référence vers ton application

  11. #11
    Membre averti
    Inscrit en
    Juillet 2006
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : Juillet 2006
    Messages : 33
    Par défaut
    En fait... Comment lui passer une référence vers mon application si il ne connait pas ce type de donnée ?

    J'ai bien essayé un Imports monnamespace mais ça n'y fais rien...

    Je ne sais pas si je m'exprime assez clairement :s


    Edit:

    J'ai résolu mon problème... je n'ajoutais pas mon assembly aux paramètres de compilation. Maintenant que c'est fait ça marche beaucoup mieux !

  12. #12
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Il faut que l'interface soit dans un assembly à part, pour que le script que tu compiles puisse le référencer

    Tu crées un nouveau projet de type Bibliothèque de classes (appelons le ScriptInterop)
    Dedans, tu crées une interface qui représente l'appli, ou du moins un objet qui permet de communiquer avec l'appli (appelons la par exemple IHostApplication), et une autre qui représente le script (par exemple IScript)
    Mettons que l'interface IScript définit une fonction d'initialisation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public interface IScript
    {
        void InitScript(IHostApplication hostApp);
    }

    Ton appli référence ScriptInterop et implémente IHostApplication
    Quand tu compiles dynamiquement le script, tu ajoutes ScriptInterop dans les références. La classe du script doit implémenter IScript.
    Quand tu as compilé la classe du script, tu en crées une nouvelle instance, et tu appelles InitScript en passant en paramètre l'objet qui fait la communication entre le script et l'appli (et qui implémente IHostApplication)

  13. #13
    Membre averti
    Inscrit en
    Juillet 2006
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : Juillet 2006
    Messages : 33
    Par défaut
    La différence est elle grosse entre utiliser une interface et passer directement une référence d'un objet?

  14. #14
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par Felloweis Voir le message
    La différence est elle grosse entre utiliser une interface et passer directement une référence d'un objet?
    euh... je suis pas sûr de bien comprendre ta question
    tu es sûr que tu sais ce que c'est qu'une interface ?

  15. #15
    Membre averti
    Inscrit en
    Juillet 2006
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : Juillet 2006
    Messages : 33
    Par défaut
    Une interface ça regroupe les références vers les membres & méthodes d'une classe non?

  16. #16
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par Felloweis Voir le message
    Une interface ça regroupe les références vers les membres & méthodes d'une classe non?
    Si on veut... disons plutôt que c'est un contrat qu'une classe doit respecter si elle implémente l'interface. Ca permet notamment de manipuler un objet dont on sait qu'il a certaines fonctionnalités (car il implémente l'interface), sans pour autant connaitre son type effectif. Par exemple si la classe MonScript implémente IScript, on peut manipuler une instance de MonScript via une variable IScript.
    En l'occurence, il faut que ton application propose une interface au script, car tu ne veux pas que le script accède à toute l'application, seulement certaines parties (question de sécurité). De même, il faut que l'application puisse manipuler le script (l'exécuter par exemple), en faisant abstraction de la classe réelle qui contient le script.

    Ce sera plus clair avec un exemple...
    - On crée un "Interop", de type bibliothèque de classes, qui contient les interfaces de "communication" entre le script et l'application hôte. Dedans on crée ces 2 interfaces :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    namespace Interop
    {
        public interface IHostApplication
        {
            Form MainWindow { get; }
        }
        public interface IScript
        {
            void Run(IHostApplication hostApp);
        }
    }
    (évidemment c'est juste un exemple, en pratique il faudrait proposer un peu plus de fonctionnalités...)

    - On crée une application "hôte" qui peut exécuter des scripts. Pour ça il faut qu'il y ait une classe qui implémente IHostApplication. Pour cet exemple, on va faire l'implémentation dans la Form principale (même si en pratique il vaudrait mieux créer une classe "proxy").
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public partial class Form1 : Form, IHostApplication
    {
        #region IHostApplication Membres
        public Form MainWindow
        {
            get { return this; }
        }
     
        #endregion
     
    ...
     
    }
    On crée aussi une méthode pour compiler le script (sûrement à améliorer, c'est juste pour montrer le principe) :
    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
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
            private IScript CompileScript(string scriptCode)
            {
                CodeDomProvider provider = CodeDomProvider.CreateProvider("C#");
                CompilerParameters prm = new CompilerParameters();
                prm.GenerateExecutable = false;
                prm.GenerateInMemory = true;
                foreach (Assembly refasm in AppDomain.CurrentDomain.GetAssemblies())
                {
                    prm.ReferencedAssemblies.Add(refasm.Location);
                }
                CompilerResults results = provider.CompileAssemblyFromSource(prm, new string[] { scriptCode });
                if (results.Errors.Count > 0)
                {
                    StringBuilder sb = new StringBuilder();
                    foreach (CompilerError err in results.Errors)
                    {
                        sb.AppendLine(err.ToString());
                    }
                    MessageBox.Show(sb.ToString());
                }
                else
                {
                    Type tScript = null;
                    foreach (Type t in results.CompiledAssembly.GetTypes())
                    {
                        if (t.GetInterface("IScript") != null)
                        {
                            tScript = t;
                            break;
                        }
                    }
                    if (tScript == null)
                    {
                        MessageBox.Show("Aucun type trouvé implémentant l'interface IScript");
                    }
                    else
                    {
                        IScript script = Activator.CreateInstance(tScript) as IScript;
                        if (script == null)
                        {
                            MessageBox.Show("Impossible de créer une instance du script");
                        }
                        else
                        {
                            return script;
                        }
                    }
                }
     
                return null;
            }
    Pour tester, on crée une textbox pour taper le code du script, et un bouton pour l'exécuter :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
            private void button1_Click(object sender, EventArgs e)
            {
                IScript script = CompileScript(textBox1.Text);
                if (script != null)
                {
                    script.Run(this);
                }
     
            }
    Ensuite, pour faire un script, il faut juste faire une classe qui implémente IScript :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    using Interop;
    using System.Windows.Forms;
     
    class unScript : IScript
    {
        public void Run(IHostApplication hostApp)
        {
            MessageBox.Show("Hello world from " + hostApp.MainWindow.Text + " ! ");
        }
    }
    Evidemment c'est juste une des solutions possibles... tu pourrais aussi, par exemple, générer le squelette de la classe pour que l'utilisateur ait juste à écrire le corps de la méthode Run (attention ça rend le système moins souple...).

    Après, à toi d'enrichir l'interface IHostApplication pour que le script puisse accéder à d'autres éléments de l'application

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

Discussions similaires

  1. Variable entre deux fichiers java script
    Par Canard64 dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 12/05/2008, 15h58
  2. Variable fichier pour script bash
    Par pcsystemd dans le forum Shell et commandes GNU
    Réponses: 5
    Dernier message: 23/04/2008, 14h10
  3. Nom de fichier de script.
    Par jean_bruder dans le forum VBScript
    Réponses: 3
    Dernier message: 18/09/2007, 19h21
  4. [Upload] Upload fichier [nouveau script]
    Par Begood dans le forum Langage
    Réponses: 10
    Dernier message: 02/03/2006, 11h28

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