OVH Cloud OVH Cloud

Evaluation d'expression arithmétiques

12 réponses
Avatar
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 :)

10 réponses

1 2
Avatar
Paul Bacelar
Utilisation de CodeDom
http://msdn.microsoft.com/msdnmag/issues/03/02/CodeDOM/
--
Paul Bacelar

"Atma" wrote in message
news:
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 :)


Avatar
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 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 "Evalw (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" a écrit dans le message de news:

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 :)


Avatar
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 www.lua.org)
pour c++) ?

Merci en tout cas des réponses :)

"Simon Mourier" a écrit :

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 "Evalw (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" a écrit dans le message de news:

> 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 :)





Avatar
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 "Evalw (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" a écrit dans le message de news:

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 :

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 "Evalw (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" a écrit dans le message de news:

> 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 :)







Avatar
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 !
Avatar
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 >system32msscript.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" a écrit dans le message de news:

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 !


Avatar
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 :

Pour voir cette classe en détail, il est plus simple d'ajouter une référence
sur l'objet COM <repertoire windows >system32msscript.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" a écrit dans le message de news:

> 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 !





Avatar
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 :)
Avatar
Atma
petite rectification ...

uneVariableVB$
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)
Avatar
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):
http://blogs.msdn.com/ericlippert/archive/2003/09/15/52996.aspx


Simon.
www.softfluent.com


"Atma" a écrit dans le message de news:

petite rectification ...

uneVariableVB$
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)



1 2