Quel est le meilleur langage de script à intégrer dans une application de bureau C #? [fermé]

98

Nous écrivons une application de bureau complexe et riche et devons offrir une flexibilité dans les formats de rapport, nous avons donc pensé que nous allions simplement exposer notre modèle objet à un langage de script. C'était à l'époque où cela signifiait VBA (qui est toujours une option), mais le dérivé de code géré VSTA (je pense) semble s'être fané sur la vigne.

Quel est maintenant le meilleur choix pour un langage de script intégré sur Windows .NET?

Ewan Makepeace
la source
FWIW, j'ai commencé avec l'approche de la réponse de @ GrantPeter, utilisé un AppDomain pour permettre le déchargement, géré le renouvellement du bail des objets interdomaines et manipulé les mesures de sécurité du sandbox. Le script compilé peut appeler des méthodes dans le programme principal, à travers la limite AppDomain. L'expérience peut être trouvée ici: github.com/fadden/DynamicScriptSandbox
fadden

Réponses:

24

J'ai utilisé CSScript avec des résultats étonnants. Cela évite vraiment d'avoir à faire des liaisons et d'autres éléments de bas niveau dans mes applications scriptables.

Hector Sosa Jr
la source
1
J'utilise CS-Script en production depuis plus d'un an et il a très bien fonctionné.
David Robbins
Btw - pour activer la prise en charge des scripts C #, vous pouvez soit intégrer la bibliothèque de scripts C # à l'intérieur, soit créer vous-même une compilation de scripts C #. J'ai fait un compilateur de script C # léger similaire dans mon propre projet ici: sourceforge.net/p/syncproj/code/HEAD/tree/CsScript.cs La compilation de script C # elle-même est un peu lente (que par exemple en comparant à .Lua), rend sens pour éviter une étape de compilation supplémentaire si elle n'est pas nécessaire.
TarmoPikaro
114

Personnellement, j'utiliserais C # comme langage de script. Le framework .NET (et Mono, merci Matthew Scharley) inclut en fait les compilateurs pour chacun des langages .NET dans le framework lui-même.

Fondamentalement, il y a 2 parties à la mise en œuvre de ce système.

  1. Permettre à l'utilisateur de compiler le code Ceci est relativement facile, et peut être fait en seulement quelques lignes de code (bien que vous souhaitiez peut-être ajouter une boîte de dialogue d'erreur, ce qui représenterait probablement quelques dizaines de lignes de code supplémentaires, selon la manière dont vous le voulez).

  2. Créer et utiliser des classes contenues dans l'assembly compilé C'est un peu plus difficile que l'étape précédente (nécessite un peu de réflexion). Fondamentalement, vous devez simplement traiter l'assembly compilé comme un "plug-in" pour le programme. Il existe de nombreux didacticiels sur différentes façons de créer un système de plug-in en C # (Google est votre ami).

J'ai implémenté une application "rapide" pour montrer comment vous pouvez implémenter ce système (comprend 2 scripts de travail!). Ceci est le code complet de l'application, il suffit d'en créer un nouveau et de coller le code dans le fichier "program.cs". À ce stade, je dois m'excuser pour le gros morceau de code que je suis sur le point de coller (je n'avais pas l'intention qu'il soit si grand, mais je me suis un peu emporté avec mes commentaires)


using System;
using System.Windows.Forms;
using System.Reflection;
using System.CodeDom.Compiler;

namespace ScriptingInterface
{
    public interface IScriptType1
    {
        string RunScript(int value);
    }
}

namespace ScriptingExample
{
    static class Program
    {
        /// 
        /// The main entry point for the application.
        /// 
        [STAThread]
        static void Main()
        {

            // Lets compile some code (I'm lazy, so I'll just hardcode it all, i'm sure you can work out how to read from a file/text box instead
            Assembly compiledScript = CompileCode(
                "namespace SimpleScripts" +
                "{" +
                "    public class MyScriptMul5 : ScriptingInterface.IScriptType1" +
                "    {" +
                "        public string RunScript(int value)" +
                "        {" +
                "            return this.ToString() + \" just ran! Result: \" + (value*5).ToString();" +
                "        }" +
                "    }" +
                "    public class MyScriptNegate : ScriptingInterface.IScriptType1" +
                "    {" +
                "        public string RunScript(int value)" +
                "        {" +
                "            return this.ToString() + \" just ran! Result: \" + (-value).ToString();" +
                "        }" +
                "    }" +
                "}");

            if (compiledScript != null)
            {
                RunScript(compiledScript);
            }
        }

        static Assembly CompileCode(string code)
        {
            // Create a code provider
            // This class implements the 'CodeDomProvider' class as its base. All of the current .Net languages (at least Microsoft ones)
            // come with thier own implemtation, thus you can allow the user to use the language of thier choice (though i recommend that
            // you don't allow the use of c++, which is too volatile for scripting use - memory leaks anyone?)
            Microsoft.CSharp.CSharpCodeProvider csProvider = new Microsoft.CSharp.CSharpCodeProvider();

            // Setup our options
            CompilerParameters options = new CompilerParameters();
            options.GenerateExecutable = false; // we want a Dll (or "Class Library" as its called in .Net)
            options.GenerateInMemory = true; // Saves us from deleting the Dll when we are done with it, though you could set this to false and save start-up time by next time by not having to re-compile
            // And set any others you want, there a quite a few, take some time to look through them all and decide which fit your application best!

            // Add any references you want the users to be able to access, be warned that giving them access to some classes can allow
            // harmful code to be written and executed. I recommend that you write your own Class library that is the only reference it allows
            // thus they can only do the things you want them to.
            // (though things like "System.Xml.dll" can be useful, just need to provide a way users can read a file to pass in to it)
            // Just to avoid bloatin this example to much, we will just add THIS program to its references, that way we don't need another
            // project to store the interfaces that both this class and the other uses. Just remember, this will expose ALL public classes to
            // the "script"
            options.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);

            // Compile our code
            CompilerResults result;
            result = csProvider.CompileAssemblyFromSource(options, code);

            if (result.Errors.HasErrors)
            {
                // TODO: report back to the user that the script has errored
                return null;
            }

            if (result.Errors.HasWarnings)
            {
                // TODO: tell the user about the warnings, might want to prompt them if they want to continue
                // runnning the "script"
            }

            return result.CompiledAssembly;
        }

        static void RunScript(Assembly script)
        {
            // Now that we have a compiled script, lets run them
            foreach (Type type in script.GetExportedTypes())
            {
                foreach (Type iface in type.GetInterfaces())
                {
                    if (iface == typeof(ScriptingInterface.IScriptType1))
                    {
                        // yay, we found a script interface, lets create it and run it!

                        // Get the constructor for the current type
                        // you can also specify what creation parameter types you want to pass to it,
                        // so you could possibly pass in data it might need, or a class that it can use to query the host application
                        ConstructorInfo constructor = type.GetConstructor(System.Type.EmptyTypes);
                        if (constructor != null && constructor.IsPublic)
                        {
                            // lets be friendly and only do things legitimitely by only using valid constructors

                            // we specified that we wanted a constructor that doesn't take parameters, so don't pass parameters
                            ScriptingInterface.IScriptType1 scriptObject = constructor.Invoke(null) as ScriptingInterface.IScriptType1;
                            if (scriptObject != null)
                            {
                                //Lets run our script and display its results
                                MessageBox.Show(scriptObject.RunScript(50));
                            }
                            else
                            {
                                // hmmm, for some reason it didn't create the object
                                // this shouldn't happen, as we have been doing checks all along, but we should
                                // inform the user something bad has happened, and possibly request them to send
                                // you the script so you can debug this problem
                            }
                        }
                        else
                        {
                            // and even more friendly and explain that there was no valid constructor
                            // found and thats why this script object wasn't run
                        }
                    }
                }
            }
        }
    }
}

Grant Peters
la source
2
Savez-vous si cela fonctionnera également en Mono ou est-ce uniquement disponible sur .NET?
Matthew Scharley
4
Pour info, et pour tous ceux qui sont curieux, oui, cela compile et fonctionne très bien sur Mono. Seulement besoin de la référence système pour les parties de compilation.
Matthew Scharley
3
Faire cela pollue l'AppDomain
Daniel Little
4
@Lavinski Si vous ne voulez pas qu'il pollue votre AppDomain, alors créez simplement un nouveau (ce qui est probablement une bonne idée de toute façon afin que vous puissiez placer une sécurité plus stricte sur les "scripts")
Grant Peters
3
@Lander - C'est extrêmement léger. Le code ci-dessus est un programme entier qui prend en charge le "scripting". csscript.neton dirait que c'est une sorte de wrapper dessus. Il s'agit essentiellement d'une implémentation simple. Je pense qu'une meilleure question serait "qu'est-ce que csscript.net fait pour moi et que ce n'est pas le cas". Je ne sais pas ce que fait csscript, mais ils savent certainement ce que fait le code ci-dessus ici, ils l'ont (ou quelque chose d'extrêmement similaire) dans leur bibliothèque.
Grant Peters
19

Le moteur PowerShell a été conçu pour être facilement intégré dans une application afin de la rendre scriptable. En fait, l'interface de ligne de commande PowerShell est simplement une interface textuelle vers le moteur.

Edit: Voir https://devblogs.microsoft.com/powershell/making-applications-scriptable-via-powershell/

Rodrick Chapman
la source
Je pense que c'est la meilleure solution car elle n'ajoute pas d'objets à AppDomain. Dans .Net, vous ne pouvez jamais décharger des assemblys ou des classes.
Daniel Little
12

Langue boo .

sauter
la source
1
Ça a l' air
kristianp
@kristianp à partir de maintenant, il y a quelques commits chaque mois sur le projet (jusqu'à il y a encore un mois). Alors peut-être qu'il a perdu un peu de traction, mais il semble toujours vivant.
Tamás Szelei
8

Mon langage de script de choix serait Lua ces jours-ci. Il est petit, rapide, propre, entièrement documenté, bien pris en charge, a une grande communauté , il est utilisé par de nombreuses grandes entreprises du secteur (Adobe, Blizzard, EA Games), ça vaut vraiment le coup d'essayer.

Pour l'utiliser avec les langages .NET, le projet LuaInterface vous fournira tout ce dont vous avez besoin.

Remo.D
la source
1
Lua est également utilisé pour le script dans Garry's Mod, qui est un excellent jeu :)
lâche anonyme
2

IronRuby comme mentionné ci-dessus. Un projet intéressant pour moi en tant que programmeur C # est le support C # Eval en Mono . Mais il n'est pas encore disponible (fera partie de Mono 2.2).

Borek Bernard
la source
2

Un autre vote pour IronPython. L'intégrer est simple, l'interopérabilité avec les classes .Net est simple et, eh bien, c'est Python.

Robert Rossney
la source
1

Je peux suggérer S # que je maintiens actuellement. Il s'agit d'un projet open source, écrit en C # et conçu pour les applications .NET.

Initialement (2007-2009), il était hébergé sur http://www.codeplex.com/scriptdotnet , mais récemment il a été déplacé vers github.

Peter
la source
Merci d'avoir publié votre réponse! Veuillez lire attentivement la FAQ sur l'auto-promotion . Notez également qu'il est nécessaire de publier une clause de non-responsabilité chaque fois que vous créez un lien vers votre propre site / produit.
Andrew Barber
Merci pour les conseils Andrew. L'une des réponses précédentes contient un lien obsolète vers ce langage de script. Pour une raison quelconque, je ne peux pas ajouter de commentaire à la réponse originale, j'en ai donc publié un nouveau pour fournir le lien correct.
Peter
1

Essayez Ela . Il s'agit d'un langage fonctionnel similaire à Haskell et peut être intégré à n'importe quelle application .Net. Même il a un IDE simple mais utilisable.

Алексей Богатырев
la source
0

Je viens de créer un plugin pour un client, lui permettant d'écrire du code C # dans des modules qui agissent comme VBA le fait pour Office.


la source
0

J'ai déjà utilisé Lua ; dans une application Delphi, mais il peut être intégré dans de nombreuses choses. Il est utilisé dans Photoshop Lightroom d'Adobe .

Tony
la source
0

J'aime les scripts avec C # lui-même . Maintenant, en 2013, il existe un assez bon support pour les scripts C #, de plus en plus de bibliothèques sont disponibles.

Mono prend en charge le script de code C # et vous pouvez l'utiliser avec .NET en incluant simplement le Mono.CSharp.dlldans votre application. Pour l'application de script C # que j'ai créée, consultez CShell

Consultez également le `ScriptEngine 'dans Roslyn qui est de Microsoft, mais ce n'est que CTP.

Comme certains l'ont déjà mentionné, CS-Script existe également depuis un certain temps.

Lukebuehler
la source