hilpers


  hilpers > microsoft.* > microsoft.dotnet.csharp

 #1  
08/06/2005, 18h34
Atma
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  
09/06/2005, 01h47
Paul Bacelar
Utilisation de CodeDom
[..]
 #3  
09/06/2005, 11h54
Simon Mourier
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 [..])

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.
[..]

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
[..]

"Atma" <Atma> a écrit dans le message de news:
2F03A503-BAE1-4F64-B035-5FA4C43E451E...
[..]
 #4  
09/06/2005, 15h43
Atma
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 [..])
pour c++) ?

Merci en tout cas des réponses :)

"Simon Mourier" a écrit :
[..]
 #5  
09/06/2005, 17h59
Simon Mourier
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.
[..]

"Atma" <Atma> a écrit dans le message de news:
4B52C7F3-8C77-4E73-B9E9-67FE3C3A304F...
[..]
 #6  
09/06/2005, 18h34
Atma
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  
10/06/2005, 08h48
Simon Mourier
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".

[..]
[..]
[..]

Simon.
[..]

"Atma" <Atma> a écrit dans le message de news:
926B74CC-2315-444A-A059-B47616822C4D...
[..]
 #8  
10/06/2005, 10h30
Atma
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  
13/06/2005, 12h37
Atma
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  
13/06/2005, 12h55
Atma
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  
13/06/2005, 17h31
Simon Mourier
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):
[..]

Simon.
[..]

"Atma" <Atma> a écrit dans le message de news:
6E89625F-6BB7-4C37-8699-9D26BBF670BA...
[..]
 #12  
13/06/2005, 18h27
Atma
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 :
[..]
(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 :)

Discussions similaires
Un problème d'ordre d'évaluation des éléments d'une expression

Evaluation d'une expression constante

Module Fp . évaluation d'une expression en un point

Erreur : l'évaluation de l'expression ...


Fuseau horaire GMT +2. Il est actuellement 07h59. | Privacy Policy