 |
|
 |
Say you had
if (k == 1 && n == 2)
{
}
as a string, how would you make it to code in a function?
So instead of creating a new namespace and stuff, how do you replace a string at a given position with it's working code representative?
So what I want is
string string = "if (k == 1 && n == 2)\n{\n\n// do things\n\n};\n";
to be replaced with
if (k == 1 && n == 2)
{
}
at this very position.
|
|
|
|
 |
|
 |
How does one go about exposing a public class to the evaluated code (e.g. to enable scripting for a program)
Namely hooking events.
Cheers
|
|
|
|
 |
|
 |
Hi Mark (and others),
I noticed your past on CodeProject.com regarding the code that can be used to create an "Eval"-type function in C#. I'm trying to utilize the "EvalToObject" method in that I want to convert a statement similar to:
document.Reports.Add(new EandG_MonthlyReport(document));
where the class name "EandG_MonthReport" is a string variable.
How would I set this up?
I've tried code similar to:
object o = Evaluator.EvalToObject("document.Reports.Add(new " + WebReport.PDFReportAppClassName.ToString() + "(document))");
where "WebReport.PDFReportAppClassName.ToString() " is the name of the class I want to instantiate, but I get errors stating " variable is not defined."
Your help is greatly appreciated!
Thank you,
Kevin Gravelle
|
|
|
|
 |
|
 |
think u first!
today i made a test ,but i find the same code didn't work the same.
when i do it in a winform ,it's ok.
but when i do it in a webForm,it gives message like "can't find "customer.dll"
the code:
public Assembly CreateAssembly(string sourceCode,string dllName)
{
if (sourceCode.Length == 0)
{
throw new System.Exception("no source code");
}
CodeDomProvider codeProvider = null;
codeProvider = new CSharpCodeProvider();
ICodeCompiler compiler = codeProvider.CreateCompiler();
CompilerParameters compilerParams = new CompilerParameters();
compilerParams.CompilerOptions = "/target:library";
compilerParams.OutputAssembly = dllName;
compilerParams.GenerateExecutable = false;
compilerParams.GenerateInMemory = true;
compilerParams.IncludeDebugInformation = false;
compilerParams.ReferencedAssemblies.Add( "mscorlib.dll");
compilerParams.ReferencedAssemblies.Add( "System.dll");
compilerParams.ReferencedAssemblies.Add( "System.Data.dll" );
compilerParams.ReferencedAssemblies.Add( "System.Drawing.dll" );
compilerParams.ReferencedAssemblies.Add( "System.Xml.dll" );
compilerParams.ReferencedAssemblies.Add( "Neighbor.Model.dll" );
CompilerResults results = compiler.CompileAssemblyFromSource(
compilerParams,
sourceCode );
string errors = "" ;
if (results.Errors.Count > 0)
{
foreach (CompilerError error in results.Errors)
errors =errors + error.ErrorText ;
throw new Exception(errors);
}
Assembly generatedAssembly = results.CompiledAssembly;
return generatedAssembly;
}
public object GetObject(string sourceCode,string objectName )
{
//Assembly asm =this.CreateAssembly(sourceCode,"test.dll");
Assembly asm =this.CreateAssembly(sourceCode);
object o = asm.CreateInstance( objectName );
return o ;
}
public Assembly CreateAssembly(string strRealSourceCode)
{
//Create an instance whichever code provider that is needed
CodeDomProvider codeProvider = null;
codeProvider = new CSharpCodeProvider();
//create the language specific code compiler
ICodeCompiler compiler = codeProvider.CreateCompiler();
//add compiler parameters
CompilerParameters compilerParams = new CompilerParameters();
compilerParams.CompilerOptions = "/target:library"; // you can add /optimize
compilerParams.GenerateExecutable = false;
compilerParams.GenerateInMemory = true;
compilerParams.IncludeDebugInformation = false;
// add some basic references
compilerParams.ReferencedAssemblies.Add( "mscorlib.dll");
compilerParams.ReferencedAssemblies.Add( "System.dll");
compilerParams.ReferencedAssemblies.Add( "System.Data.dll" );
compilerParams.ReferencedAssemblies.Add( "System.Drawing.dll" );
compilerParams.ReferencedAssemblies.Add( "System.Xml.dll" );
compilerParams.ReferencedAssemblies.Add( "CC.dll" );
compilerParams.ReferencedAssemblies.Add( "System.Data1.dll" );
compilerParams.ReferencedAssemblies.Add( "PDT.Persist.dll" );
//actually compile the code
CompilerResults results = compiler.CompileAssemblyFromSource(
compilerParams,
strRealSourceCode );
string e = "" ;
//Do we have any compiler errors
if (results.Errors.Count > 0)
{
foreach (CompilerError error in results.Errors)
{
e = e + error.ErrorText;
}
throw new Exception(e);
}
//get a hold of the actual assembly that was generated
Assembly generatedAssembly = results.CompiledAssembly;
return generatedAssembly;
}
|
|
|
|
 |
|
 |
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
|
|
|
|
 |
|
|
 |
|
 |
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.
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Microsoft.CSharp;
namespace Test
{
///
/// C# Code Evaluator
/// Based on work by Kim Hauser found at http://www.codeproject.com/csharp/evalcscode.asp
///
class CSEvaluator
{
///
/// Assemblies are what follow "using"
///
public List Assemblies;
///
/// References are in the Solution Explorer in the References folder
///
public List References;
///
/// Namespace to evaluate in, in case you want to be able to access external classes
///
public string Namespace;
public CSEvaluator()
{
References = new List();
// Adding default References
References.Add("System");
References.Add("System.Drawing");
References.Add("System.Windows.Forms");
References.Add("System.Xml");
Assemblies = new List();
// Adding default assemblies
Assemblies.Add("System");
Assemblies.Add("System.Drawing");
Assemblies.Add("System.Drawing.Drawing2D"); // notice that Drawing2D is not in the list of references
Assemblies.Add("System.Windows.Forms"); // this is because System.Drawing is the reference for it
Assemblies.Add("System.Xml");
Namespace = this.GetType().Namespace.ToString();
}
///
/// Evaluates C# Code
///
/// The Code to evaluate
/// parameter string, i.e. "string sCSCode, string sParms, object[] oParms"
/// array of parameter objects
///
public object Eval(string sCSCode, string sParms, object[] oParms)
{
CompilerParameters cp = new CompilerParameters();
// load references
foreach (string r in References)
cp.ReferencedAssemblies.Add(r + ".dll");
cp.CompilerOptions = "/t:library";
cp.GenerateInMemory = true;
StringBuilder sb = new StringBuilder("");
// load assemblies
foreach (string s in Assemblies)
sb.Append("using " + s + ";\n");
sb.Append("\nnamespace " + Namespace + "\n{\n");
sb.Append("\tpublic class temp_Eval\n\t{\n");
sb.Append("\t\tpublic object Eval(" + sParms + ")\n\t\t{\n");
sb.Append("\t\t\treturn " + sCSCode + "; \n");
sb.Append("\t\t}\n");
sb.Append("\t}\n");
sb.Append("}\n");
CompilerResults cr = CodeDomProvider.CreateProvider("CSharp").CompileAssemblyFromSource(cp, sb.ToString());
if (cr.Errors.Count > 0)
{
MessageBox.Show("ERROR: " + cr.Errors[0].ErrorText,
"Error evaluating cs code", MessageBoxButtons.OK,
MessageBoxIcon.Error);
return null;
}
// *** Below this point is a work in progress, watch out for falling debris ***
//AppDomain evalDomain = AppDomain.CreateDomain("evalDomain");
System.Reflection.Assembly a = cr.CompiledAssembly;
//evalDomain.DefineDynamicAssembly(a.GetName(), System.Reflection.Emit.AssemblyBuilderAccess.Run); // problem here can be solved with MarshalByRefObject
//object o = evalDomain.CreateInstance(a.GetName().ToString(), Namespace + ".temp_Eval"); // it probably won't work like this
object o = a.CreateInstance(Namespace + ".temp_Eval");
Type t = o.GetType();
System.Reflection.MethodInfo mi = t.GetMethod("Eval");
object ec = mi.Invoke(o, oParms);
//AppDomain.Unload(evalDomain);
return ec;
}
}
}
|
|
|
|
 |
|
 |
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!!"
|
|
|
|
 |