|
compilerParams.ReferencedAssemblies.Add(HttpContext.Currrent.Server.MapPath( "bin/CC.dll" ));
|
|
|
|
|
Nice work. Thanks for sharing the idea. But I think you must update the article with its uses.
I was aware of dynamic compilation, but kept scratching my head on what the use of this eval function...until I could point its synonymous usage in javascript
For people who want to know eval's real power(basically dynamic compilation) , see the link below
http://builder.com.com/5100-6371-5169823.html[^]
|
|
|
|
|
Way too slow to compile on the fly! Eval.JScriptEvaluate is so much better. Too bad it has been obsoleted in .NET 2.0.
|
|
|
|
|
You sort of anihilate your comment in the last sentence !
|
|
|
|
|
After a little research, JScriptEval can still be used. The code below accomplishes this.
using System;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.JScript;
namespace Expressions
{
public class JScriptEvaluator
{
public static int EvalToInteger(string statement)
{
string s = EvalToString(statement);
return int.Parse(s.ToString());
}
public static double EvalToDouble(string statement)
{
string s = EvalToString(statement);
return double.Parse(s);
}
public static string EvalToString(string statement)
{
object o = EvalToObject(statement);
return o.ToString();
}
public static object EvalToObject(string statement)
{
return _evaluatorType.InvokeMember(
"Eval",
BindingFlags.InvokeMethod,
null,
_evaluator,
new object[] { statement }
);
}
static JScriptEvaluator()
{
CodeDomProvider provider = new Microsoft.JScript.JScriptCodeProvider();
CompilerParameters parameters;
parameters = new CompilerParameters();
parameters.GenerateInMemory = true;
CompilerResults results;
results = provider.CompileAssemblyFromSource(parameters, _jscriptSource);
Assembly assembly = results.CompiledAssembly;
_evaluatorType = assembly.GetType("Evaluator.Evaluator");
_evaluator = Activator.CreateInstance(_evaluatorType);
}
private static object _evaluator = null;
private static Type _evaluatorType = null;
private static readonly string _jscriptSource =
@"package Evaluator
{
class Evaluator
{
public function Eval(expr : String) : String
{
return eval(expr);
}
}
}";
}
}
Mark
|
|
|
|
|
Mark,
Your version is brilliant .
I needed to evaluate lots of conditions inside a big loop, and the JScriptEvaluator returns instantly. The original is much too slow when you need to evaluate a number of statements inside a loop.
Well done
Graham Harrison
|
|
|
|
|
Code listed by Mark is actually from http://odetocode.com/code/80.aspx "An Eval Function for C# using JScript.NET (JavaScript)"
Michael Freidgeim.
Blog: http://geekswithblogs.net/mnf/
|
|
|
|
|
A new version arrived with AppDomain implemented > So no memory issue should happen anymore!
|
|
|
|
|
Can you tell me where is this new version you spoke about in this thread?
Also, what is the downside of either this version or the Jscript version beside speed?
And now that you've seen both methods, which one would you prefer to use?
And if anyone is interested, I can certainly tell you how a utility like this can be used. We are in the middle of a conversion of a large App to C#, and we have built into our previous App a Query Builder which "evaluates" users, currently displayed table values, etc. and has an Expression feature that allows queries to be built on the fly with custom expressions in the where or select clauses.
My concern has been the memory issue. But we also have an import wizard that may process and "crunch" data from outside sources and often has to "Evaluate" stuff and it could process 1000s of records, so speed is another issue I am concerned with.
Thanks for your input.
Bob Bartel
MarketWare Systems
|
|
|
|
|
Can you please tell me what you mean by "new version arrived with AppDomain implemented..."?
Are you referring to C# or your Eval Function? If Eval Function, can I get a copy of the new version?
Thanks.
Bob Bartel
MarketWare Software
bob@marketware.org
Sandy, Utah USA
|
|
|
|
|
You dont need any dll.
It is excellent idea, but so dangerous.
Tkx
.
|
|
|
|
|
Do you think that this is an appropriate function for evaluating mathematical expressions? I am creating a calculator and the use of an Eval function makes life a lot simpler however I am unsure as to if this eval method is the best way to do it.
|
|
|
|
|
I'm a bit late, but what kind of expressions do you want to eavl? Are they really complicate or like 100 * 1000 / 20, because if you need variables and complex opperation, it would be a good thing to think about a little script language witch wrapps your math expression (inputed as one expression or via config (ie. hp style)) and then executes a genereted code over the eval function. If you just want to calculate some numbers you can write a text parser and do the calculation without eval.
IMPORTANT:
If you use this (thi 1st) source example (2nd is coming soon - sooon!!!), make sure to load the new assembly into an new AppDomain, else it will eat up all your memory
greez kim
|
|
|
|
|
Thanks for all your response. Sorry for the long time it took to answere and the less documentation i'd supply with the example, but I'm working on a real interesting project at the moment and it's really time consuming, at least for me . To this example and the code provided: this is just a mix of a vb.net example and some c# snippets i've found, and should show a basic meaning of dynamically compiling code in c# (it's a conversion from vb.net). - till then use the EvalCSCode.cs class and customize to your needs :->
I agree with some of you, that there should be more introducion to the problem it solves. I think I'll update this topic soon with an new example and text. thanx again for review and keep on coding & posting - regards dave
|
|
|
|
|
It's great, but... why don't you use a static method? I think it would be faster than a new instance.
|
|
|
|
|
looks static to me:
public static object Eval(string sCSCode)
|
|
|
|
|
No... He meant the stub class and its method should be static. Those created on the fly.
|
|
|
|
|
It's Excellent, but every time when the func is called, a temp assembly will be created and loaded into the application, these assemblies will stay there until current appdomain unload. The more the func is callled, the more temp assemblies will be loaded. So, if current appdomain is the default appdomain of the application then ...
|
|
|
|
|
|
Used this is a project I'm working on. It's a slight modification of what you posted.
I also tried to figure out the AppDomain, this is where I got when I ran into a brick wall.
In order to load the code into the new AppDomain, you will need 2 classes, the first class creates the AppDomain, and loads the 2nd class into it, similar to what I have at the bottom. The second class will inherit MarshalByRefObject and will do all the dynamic compilation.
When/if I get around to finishing this, I'll post it as well.
<br />
using System;<br />
using System.CodeDom.Compiler;<br />
using System.Collections.Generic;<br />
using System.Text;<br />
using System.Windows.Forms;<br />
using Microsoft.CSharp;<br />
<br />
namespace Test<br />
{<br />
class CSEvaluator<br />
{<br />
public List<string> Assemblies;<br />
public List<string> References;<br />
public string Namespace;<br />
<br />
public CSEvaluator()<br />
{<br />
References = new List<string>();<br />
References.Add("System");<br />
References.Add("System.Drawing");<br />
References.Add("System.Windows.Forms");<br />
References.Add("System.Xml");<br />
<br />
Assemblies = new List<string>();<br />
Assemblies.Add("System");<br />
Assemblies.Add("System.Drawing");<br />
Assemblies.Add("System.Drawing.Drawing2D");
Assemblies.Add("System.Windows.Forms");
Assemblies.Add("System.Xml");<br />
<br />
Namespace = this.GetType().Namespace.ToString();<br />
}<br />
<br />
public object Eval(string sCSCode, string sParms, object[] oParms)<br />
{<br />
CompilerParameters cp = new CompilerParameters();<br />
<br />
foreach (string r in References)<br />
cp.ReferencedAssemblies.Add(r + ".dll");<br />
<br />
cp.CompilerOptions = "/t:library";<br />
cp.GenerateInMemory = true;<br />
<br />
StringBuilder sb = new StringBuilder("");<br />
foreach (string s in Assemblies)<br />
sb.Append("using " + s + ";\n");<br />
<br />
sb.Append("\nnamespace " + Namespace + "\n{\n");<br />
sb.Append("\tpublic class temp_Eval\n\t{\n");<br />
sb.Append("\t\tpublic object Eval(" + sParms + ")\n\t\t{\n");<br />
sb.Append("\t\t\treturn " + sCSCode + "; \n");<br />
sb.Append("\t\t}\n");<br />
sb.Append("\t}\n");<br />
sb.Append("}\n");<br />
<br />
CompilerResults cr = CodeDomProvider.CreateProvider("CSharp").CompileAssemblyFromSource(cp, sb.ToString());<br />
if (cr.Errors.Count > 0)<br />
{<br />
MessageBox.Show("ERROR: " + cr.Errors[0].ErrorText,<br />
"Error evaluating cs code", MessageBoxButtons.OK,<br />
MessageBoxIcon.Error);<br />
return null;<br />
}<br />
<br />
<br />
System.Reflection.Assembly a = cr.CompiledAssembly;<br />
object o = a.CreateInstance(Namespace + ".temp_Eval");<br />
<br />
Type t = o.GetType();<br />
System.Reflection.MethodInfo mi = t.GetMethod("Eval");<br />
<br />
object ec = mi.Invoke(o, oParms);<br />
<br />
return ec;<br />
}<br />
}<br />
}<br />
|
|
|
|
|
I havent downloaded it so far to see it working. But I really appreciate your work in advance.
I've been working on javascript for a quite long time and admire its "eval" function, and I was missing it in C#. You have really done great job having same in C#. I'll bookmark this page because I know I'll need it one day.
And as some1 said above; not every1 knows how powerful this function is.
---------
Tittle
|
|
|
|
|
This is certainly an elegant, and beautifuly simple, solution! Thank you for sharing it. However, it would be nice for most of us out here reading it if there were a bit more discussion up front about the problem that it solves. I suspect that it will not be utilized as much as it could be (or rated as high, for that matter!) because many won't realize how powerful it is.
Anyway, thanks again for giving it to us - it surely gets my "5".
Herman Chelette
"Damn the specs! Find the elegant solution!!"
|
|
|
|
|
Thanks for your comment, i think about a update of this topic in the near future. Due to my permanent lack of time i didn't post realy much - sorry for that.
|
|
|
|
|
Good article. I am curious as to whether or not you could get a list of all assemblies already in memory and reference them. That way, if a user has an eval statement against custom objects, it would still work.
|
|
|
|
|
try using this:
using System.Reflection;
Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach( Assembly assembly in loadedAssemblies ){
try{
Console.WriteLine(assembly.FullName);
}catch( TypeLoadException tlexec ){}
regards dave
|
|
|
|