|
|
||||||
|
#1
|
|
|
|
|
Bonjour,
ma question est simple : existe-t-il un évaluateur d'expression arithmétique dans les lib de c# sous .net ? Genre par exemple, j'aimerais que la String "12+13*5" me retourne 77 S'il en existe, je suis encore plus exigeant : existe-t-il carrément un évaluateur d'expression c# comme il peut en exister en php (la je suis conscient que j'en demande beaucoup... mais sait-on jamais...) ? Par exemple, le code : String toto = "hello"; EvaluateurC#.Eval("toto += \" world !\";"); System.Console.WriteLine(toto); // affiche "hello world" Question subsidiaire : si cela n'existe pas sous .net ... cela peut-il exister dans une lib gratuite ? Merci d'avance :)
|
|
#2
|
|
|
|
|
Utilisation de CodeDom
http://msdn.microsoft.com/msdnmag/issues/03/02/CodeDOM/ |
|
#3
|
|
|
|
|
Si vous n'êtes pas absolument attaché à un langage, vous pourriez réutiliser
les langages de scripts tels que VBScript, JScript (~Javascript), ou tout autre langage prenant en charge ActiveX Scripting (on trouve par exemple ActivePython, ActivePerl, ... ici http://www.activestate.com) Ceci nécessite un contrôle ActiveX peu connu "ScriptControl" (msscript.ocx). Il est en général installé par défaut avec Windows, mais il faut s'en assurer. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnexpvb/html/usingscriptcontrolmethods.asp Voici un exemple dans une application console (il faudrait faire les tests d'erreurs nécessaires) qui renvoie le résultat (qui est d'ailleurs typé, on récupère ici un Int16 par exemple). On peut aussi directement créer une référence vers le composant COM, ici je le fait en "late binding". class Class1 { [STAThread] static void Main(string[] args) { Type scriptControlType = Type.GetTypeFromProgID("scriptcontrol"); object scriptControl = Activator.CreateInstance(scriptControlType); // AllowUI = false scriptControlType.InvokeMember("AllowUI", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.SetProperty, null, scriptControl, new object[]{false}); // Language = VBScript scriptControlType.InvokeMember("Language", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.SetProperty, null, scriptControl, new object[]{"VBScript"}); string evalText = "12 + 13 * 5"; // Eval(evalText) object o = scriptControlType.InvokeMember("Eval", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.InvokeMethod, null, scriptControl, new object[]{evalText}); Console.WriteLine("Eval=" + o + " (" + o.GetType().FullName + ")"); // renvoie "Eval=77 (System.Int16)" // plus sophistiqué! création d'une fonction VBScript. string functionText = "Function MyFunc(text): MyFunc = text & \" world!\": End Function"; scriptControlType.InvokeMember("AddCode", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.InvokeMethod, null, scriptControl, new object[]{functionText}); // Run myFunc(...) string text = "Hello"; o = scriptControlType.InvokeMember("Run", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.InvokeMethod, null, scriptControl, new object[]{"MyFunc", text}); Console.WriteLine("Run=" + o + " (" + o.GetType().FullName + ")"); // renvoie "Run=Hello world! (System.String)" } } L'avantage de cette méthode c'est que vous n'avez pas besoin d'avoir recours à la compilation .NET (CodeDom) qui exige des droits pour l'utilisateur courant, l'écriture de fichiers, etc... Ici tout se passe en mémoire, et les DLL vbscript.dll et jscript.dll sont assez petites et performantes (VBScript.dll est utilisée par tous les sites ASP classiques...) Il n'existe pas à ma connaissance de "C#Script" mais vous n'en avez peut-être pas besoin. Simon www.softfluent.com "Atma" <Atma> a écrit dans le message de news: 2F03A503-BAE1-4F64-B035-5FA4C43E451E... [..] |
|
#4
|
|
|
|
|
Est-il possible de "lier" des méthodes définies en C# dans un des langages de
script cités (un peu comme lua (si vous connaissez ... sinon www.lua.org) pour c++) ? Merci en tout cas des réponses :) "Simon Mourier" a écrit : [..] |
|
#5
|
|
|
|
|
Oui c'est possible aussi. On ajoute au script un objet externe appelable par
le script. public class Class1 // notez que la classe utilisée dans AddObjet doit etre publique et avoir l'attribut ComVisible à true (c'est le cas par défaut) { [STAThread] static void Main(string[] args) { Type scriptControlType = Type.GetTypeFromProgID("scriptcontrol"); object scriptControl = Activator.CreateInstance(scriptControlType); // AllowUI = false scriptControlType.InvokeMember("AllowUI", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.SetProperty, null, scriptControl, new object[]{false}); // Language = VBScript scriptControlType.InvokeMember("Language", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.SetProperty, null, scriptControl, new object[]{"VBScript"}); string evalText = "12 + 13 * 5"; // Eval(evalText) object o = scriptControlType.InvokeMember("Eval", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.InvokeMethod, null, scriptControl, new object[]{evalText}); Console.WriteLine("Eval=" + o + " (" + o.GetType().FullName + ")"); // renvoie "Eval=77 (System.Int16)" // plus sophistiqué! string functionText = "Function MyFunc(text): MyFunc = text & \" world!\": End Function"; scriptControlType.InvokeMember("AddCode", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.InvokeMethod, null, scriptControl, new object[]{functionText}); // Run myFunc(...) string text = "Hello"; o = scriptControlType.InvokeMember("Run", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.InvokeMethod, null, scriptControl, new object[]{"MyFunc", text}); Console.WriteLine("Run=" + o + " (" + o.GetType().FullName + ")"); // renvoie "Run=Hello world! (System.String)" Class1 c1 = new Class1(); // un peu plus sophistiqué! // le nom de l'objet (ici 'csharp') devient utilisable dans tout le code ajouté au scriptcontrol. // pour info, c'est comme cela que window ou document sont gérés par Internet Explorer, ou que request, session, ... sont gérés par ASP classique. scriptControlType.InvokeMember("AddObject", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.InvokeMethod, null, scriptControl, new object[]{"csharp", c1, true}); evalText = "csharp.GetText(\"hello\")"; // un code VBScript utilisant l'objet 'csharp' qui est l'instance c1 créee plus haut. o = scriptControlType.InvokeMember("Eval", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.InvokeMethod, null, scriptControl, new object[]{evalText}); Console.WriteLine("Eval=" + o + " (" + o.GetType().FullName + ")"); // renvoie "Eval=hello from C# (System.String)" } // une méthode publique de la classe public string GetText(string text) { return text + " from C#"; } } Simon. www.softfluent.com "Atma" <Atma> a écrit dans le message de news: 4B52C7F3-8C77-4E73-B9E9-67FE3C3A304F... [..] |
|
#6
|
|
|
|
|
okip ... ça m'a l'air extrêmement intéressant ...
Juste une dernière question : quel classe est retournée par les premiere lignes Type scriptControlType = Type.GetTypeFromProgID("scriptcontrol"); object scriptControl = Activator.CreateInstance(scriptControlType); J'ai fait un affichage mais je n'obtiens que System.__ComObject (et dans MSDN il ne parlent pas énormément de cette classe ^^; ) .... Je demande ca pour aller voir un peu les méthodes disponibles pour la classe de progId "scriptControl" (notamment pour aller voir si la récupération d'un objet depuis VBScript dans C# est possible ... je suppose .... mais je préfère en etre sur ;) ) Merci encore pour tout ! |
|
#7
|
|
|
|
|
Pour voir cette classe en détail, il est plus simple d'ajouter une référence
sur l'objet COM <repertoire windows >\system32\msscript.ocx. Mon exemple utilise une approche sans référence mais cela revient en gros au même. Sinon, System.__ComObject est la classe système générique créee par le .NET Framework qui représente un runtime callable wrapper (RCW), c'est à dire une classe qui sert de proxy vers tout COM sous jacent. On peut (on doit) effectuer des cast sur cette classe pour l'utiliser, ou alors on fait des InvokeMember comme dans l'exemple quand on sait quel est l'objet. En l'occurence cet objet correspond à l'objet COM dont le progid est "ScriptControl". http://msdn.microsoft.com/library/en-us/dnexpvb/html/usingscriptcontrolmethods.asp http://www.webtropy.com/articles/art14-2.asp?Interop=MSScriptControl http://support.microsoft.com/kb/q185889/ Simon. www.softfluent.com "Atma" <Atma> a écrit dans le message de news: 926B74CC-2315-444A-A059-B47616822C4D... [..] |
|
#8
|
|
|
|
|
okip je vais bucher un peu tout ca .... mais c'est exactement ce qu'il me
faut je pense :) Merci énormément ... ca va m'éviter de me taper un compilateur pour ce que je voulais faire :) @+ "Simon Mourier" a écrit : [..] |
|
#9
|
|
|
|
|
Je reviens vous embeter puisque j'ai un petit souci ...
En effet, vous avez pu me montrer qu'il était possible de "rendre accessible" un objet C# au VBScript que l'on génère ... Maintenant, j'aimerais savoir s'il est possible de rendre accessible une variable de VBScript à C# ... .... ou plus "simplement" affecter la valeur d'une variable VBScript à un objet C# ayant été "rendu accessible" a VBScript... Je sais pas si j'ai été très clair, mais en fait, mon probleme est que j'ai un objet C# toto partagé avec VBScript (avec le nom toto...) Lorsque je fais : toto.UneMéthodeDeToto() ' aucun Problème ! toto.UneMéthodeDeToto("une chaine", 10) ' aucun Probleme ! Sub UneProcedure(param1, param2): toto.UneMéthodeDeToto(param1, param2) : End Sub ' Là probleme ! uneVariableVB = 24 toto.valeur = uneVariableVB ' Là aussi problème ! Je pense que les "objets" VB de par leur "non typage" ont beaucoup de mal à être "envoyés" a C# ... peut-on pallier a cela ? *espere* Merci énormément d'avance :) |
|
#10
|
|
|
|
|
petite rectification ...
uneVariableVB=24 toto.valeur=uneVariableVB cela fonctionne !... .... c'est donc un probleme de variables ... à savoir que tout ce que je fais pour la procédure UneProcedure(), c'est un appel du type : UneProcedure("param1", 23) |
|
#11
|
|
|
|
|
Contrairement à l'acceptation générale, VBScript (et VB mais attention tout
de même de ne pas confondre les deux) est bien un langage fortement typé, sauf que les types ne sont très pas visibles. Bref, le problème vient ici de la syntaxe VBScript qui n'est pas correcte toto.UneMéthodeDeToto(param1, param2) doit être remplacé par toto.UneMéthodeDeToto param1, param2 ou toto.UneMéthodeDeToto (param1), (param2) qui n'a pas la même signification. En effet, dans ce cas, param1 et param2 sont passés forcés par valeur, et non par référence. c'est une erreur très classique :-) pour les curieux, le pourquoi du comment se trouve ici (par le développeur de VBScript et Javascript lui-même): http://blogs.msdn.com/ericlippert/archive/2003/09/15/52996.aspx Simon. www.softfluent.com "Atma" <Atma> a écrit dans le message de news: 6E89625F-6BB7-4C37-8699-9D26BBF670BA... [..] |
|
#12
|
|
|
|
|
Ouki ... je me suis apercu (il y a pas moins de deux heures... a force de
triturer mon code dans tous les sens et a rechercher sur internet) qu'en effet cela venait de la déclaration des mes fontions et autres procédures... Tout marche impeccablement bien maintenant : j'ai un interpréteur de VBScript lié avec mon appli C# qui execute des fonctions de ce dernier parfaitement :) .... Pour les "curieux", vous pouvez trouver une archive d'un projet de "test" montrant un tel interpréteur ici : http://derf.hd.free.fr/~derf/testEvalExpr.zip (nota : ca n'est pas énormément commenté... le code est extensible a vos fonctions : il suffit d'hériter de la fonction Fonction et d'instancier une instance de votre fonction dans le tableau static _fonctionConnues de la classe GestionnaireFonctions ... tout le reste ne doit normalement pas être "touché" pour fonctionner :)) Merci encore a vous Simon :)
|
|
Fuseau horaire GMT +2. Il est actuellement 17h50. | Privacy Policy
|