Compile simple string - c#

Was just wondering if there are any built in functions in c++ OR c# that lets you use the compiler at runtime? Like for example if i want to translate:
!print "hello world";
into:
MessageBox.Show("hello world");
and then generate an exe which will then be able to display the above message? I've seen sample project around the web few years ago that did this but can't find it anymore.

It is possible using C#. Have a look at this Sample Project from the CodeProject.
Code Extract
private Assembly BuildAssembly(string code)
{
Microsoft.CSharp.CSharpCodeProvider provider = new CSharpCodeProvider();
ICodeCompiler compiler = provider.CreateCompiler();
CompilerParameters compilerparams = new CompilerParameters();
compilerparams.GenerateExecutable = false;
compilerparams.GenerateInMemory = true;
CompilerResults results = compiler.CompileAssemblyFromSource(compilerparams, code);
if (results.Errors.HasErrors)
{
StringBuilder errors = new StringBuilder("Compiler Errors :\r\n");
foreach (CompilerError error in results.Errors )
{
errors.AppendFormat("Line {0},{1}\t: {2}\n", error.Line, error.Column, error.ErrorText);
}
throw new Exception(errors.ToString());
}
else
{
return results.CompiledAssembly;
}
}
public object ExecuteCode(string code, string namespacename, string classname, string functionname, bool isstatic, params object[] args)
{
object returnval = null;
Assembly asm = BuildAssembly(code);
object instance = null;
Type type = null;
if (isstatic)
{
type = asm.GetType(namespacename + "." + classname);
}
else
{
instance = asm.CreateInstance(namespacename + "." + classname);
type = instance.GetType();
}
MethodInfo method = type.GetMethod(functionname);
returnval = method.Invoke(instance, args);
return returnval;
}

In C++ you can't use the compiler at runtime but you can embed an interpreter in your project, like CINT.

You can always do it in the dirty way, with system() and calling the compiler "gcc..." or your equivalent

Nick's suggestion is good, but there is an alternative which is probably simpler to implement (but might not be appropriate for all projects). If you can assume that your user has a compiler installed you can generate a file and then compile it using their compiler.

The .NET-framework provides a few classes which give you access to compilers and code generators for C# and VB.NET, resulting in either an assembly loaded into memory or a simple .exe-file. See CSharpCodeProvider and this article.
Alternately, you can just create the source files and compile them manually (command-line calls (system) to the compiler, makefiles).
Concerning the translation of your source: You'll have to use parsing mechanisms like regular expressions here, or use a compiler-compiler tool like Coco/R, yacc etc. (Note that under C++, boost::spirit can also be quite useful)

In C# you can create a .NET "CodeDom" tree and then compile this using the .NET compiler. This gives you full access to most features of .NET.
See the "System.CodeDom" namespace or the MSDN help for CodeCompileUnit for details.

Related

How to use incompleted types in reflection?

I want to dynamically generate the assembly, which can have functions with different structures. To be more accurate, these functions can be recursive, they can call other functions within the same assembly etc. I found the System.Reflection module which theoretically provides tools to do this, but in practice I have encountered many drawbacks for this approach. For example - I cannot generate recursive functions via TypeBuilder and MethodBuilder classes, because exception will be thrown (usage of incomplete types). I learned that I can generate selfrecursive functions via IlGenerator - but it is too cumbersome - I hoped that there is an easier way to do this.
Here is my program which demonstrates the problem (at generation of method Fact the following Exception is thrown:
Exception thrown: 'System.NotSupportedException' in mscorlib.dll
Additional information: Specified method is not supported..
Code:
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Linq.Expressions;
namespace GenericFuncs
{
public class ProgramBuilder
{
public Type createMyProgram()
{
var assmName = new AssemblyName("DynamicAssemblyExample");
var assmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assmName, AssemblyBuilderAccess.RunAndSave);
var moduleBuilder = assmBuilder.DefineDynamicModule(assmName.Name, assmName.Name + ".dll");
var myProgramType = buildMyProgram(moduleBuilder, moduleBuilder.DefineType("MyProgram", TypeAttributes.Public));
assmBuilder.Save(assmName.Name + ".dll");
return myProgramType;
}
private Type buildMyProgram(ModuleBuilder mb, TypeBuilder programBuilder)
{
buildFactFunction2(mb, mb.GetType("MyProgram"), programBuilder.DefineMethod("InfLoop", MethodAttributes.Public | MethodAttributes.Static));
buildFactFunction(mb, mb.GetType("MyProgram"), programBuilder.DefineMethod("Fact", MethodAttributes.Public | MethodAttributes.Static));
return programBuilder.CreateType();
}
private void buildFactFunction(ModuleBuilder mb, Type program_type, MethodBuilder methodBuilder)
{
var param = Expression.Parameter(typeof(int), "n");
var lambda = Expression.Lambda(Expression.Call(methodBuilder, param), param);
lambda.CompileToMethod(methodBuilder);
}
static public void my_print(string s)
{
Console.WriteLine(s);
}
private void buildFactFunction2(ModuleBuilder mb, Type program_type, MethodBuilder methodBuilder)
{
var il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldstr, "a");
il.Emit(OpCodes.Call, typeof(ProgramBuilder).GetMethod("my_print"));
il.Emit(OpCodes.Call, methodBuilder);
il.Emit(OpCodes.Ret);
}
}
class Program
{
static void Main(string[] args)
{
var pbuilder = new ProgramBuilder();
var ptype = pbuilder.createMyProgram();
Console.ReadLine();
}
}
}
Any help is appreciated.
Expressions and reflection in C# have their limitations (albeit still very powerful for simple use cases). To the best of my knowledge, Emit is the way to go if you need the functionality which you describe (even the basic requirement of emitting assemblies).
Some years ago, I used RunSharp quite effectively in some minimal dynamic code generation use cases. It takes away most of the IL pains. For example, in this code I create a proxy wrapper at runtime.
You could also have a look at what Castle Project uses for their code generation, e.g., their DynamicProxy is quite popular.
This is probably not what you are after but have you thought about CodeDom ?
The downside is it wont be truly dynamic, as you have to load the assembly
Dynamic Source Code Generation and Compilation
As pointed out by Steven Jeuris There is a great question on the differences between CodeDom and Emit Reflection.Emit vs CodeDOM
CodeDom generates C# source code and is usually used when generating code to be included as part of a solution and compiled in the IDE (for
example, LINQ to SQL classes, WSDL, XSD all work this way). In this
scenario you can also use partial classes to customize the generated
code. It is less efficient, because it generates C# source and then
runs the compiler to parse it (again!) and compile it. You can
generate code using relatively high-level constructs (similar to C#
expressions & statements) such as loops.
Reflection.Emit generates an IL so it directly produces an assembly that can be also stored only in memory. As a result is a lot more
efficient.You have to generate low-level IL code (values are stored on
stack; looping has to be implemented using jumps), so generating any
more complicated logic is a bit difficult.
Simple CodeDom Exmaple from MSDN
public Sample()
{
targetUnit = new CodeCompileUnit();
CodeNamespace samples = new CodeNamespace("CodeDOMSample");
samples.Imports.Add(new CodeNamespaceImport("System"));
targetClass = new CodeTypeDeclaration("CodeDOMCreatedClass");
targetClass.IsClass = true;
targetClass.TypeAttributes =
TypeAttributes.Public | TypeAttributes.Sealed;
samples.Types.Add(targetClass);
targetUnit.Namespaces.Add(samples);
}
public void AddFields()
{
// Declare the widthValue field.
CodeMemberField widthValueField = new CodeMemberField();
widthValueField.Attributes = MemberAttributes.Private;
widthValueField.Name = "widthValue";
widthValueField.Type = new CodeTypeReference(typeof(System.Double));
widthValueField.Comments.Add(new CodeCommentStatement(
"The width of the object."));
targetClass.Members.Add(widthValueField);
// Declare the heightValue field
CodeMemberField heightValueField = new CodeMemberField();
heightValueField.Attributes = MemberAttributes.Private;
heightValueField.Name = "heightValue";
heightValueField.Type =
new CodeTypeReference(typeof(System.Double));
heightValueField.Comments.Add(new CodeCommentStatement(
"The height of the object."));
targetClass.Members.Add(heightValueField);
}
public void GenerateCSharpCode(string fileName)
{
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CodeGeneratorOptions options = new CodeGeneratorOptions();
options.BracingStyle = "C";
using (StreamWriter sourceWriter = new StreamWriter(fileName))
{
provider.GenerateCodeFromCompileUnit(
targetUnit, sourceWriter, options);
}
}
static void Main()
{
Sample sample = new Sample();
sample.AddFields();
//sample.AddProperties();
//sample.AddMethod();
//sample.AddConstructor();
//sample.AddEntryPoint();
sample.GenerateCSharpCode(outputFileName);
}
And you could use one of several methods to run your code
private static Assembly CompileSourceCodeDom(string sourceCode)
{
CodeDomProvider cpd = new CSharpCodeProvider();
var cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("System.dll");
cp.GenerateExecutable = false;
CompilerResults cr = cpd.CompileAssemblyFromSource(cp, sourceCode);
return cr.CompiledAssembly;
}
private static void ExecuteFromAssembly(Assembly assembly)
{
Type fooType = assembly.GetType("Foo");
MethodInfo printMethod = fooType.GetMethod("Print");
object foo = assembly.CreateInstance("Foo");
printMethod.Invoke(foo, BindingFlags.InvokeMethod, null, null, CultureInfo.CurrentCulture);
}

CodeDomProvider Code Generation Fails With Certain Linq Syntax

I'm using the CodeDomProvider to compile some Linq code and execute queries dynamically. However, I'm hitting a very strange issue.
If my Linq query in the generated code looks like this everything works:
namespace Dynamic
{
using System.Linq;
using System.Collections.Generic;
public static class Query
{
public static int GetRecords()
{
MyData.Data.DataMart container = new MyData.Data.DataMart();
return (container.EventDetails).Count();
}
}
}
This compiles and runs just fine. However, if I change the linq query to the following then it fails to compile:
return (from e in container.EventDetails select e).Count();
It works fine if I put this as static code, but if I try to compile it with the CodeDomProvider it fails (and I haven't found any good method to get error messages on why it fails). I would like to use the from-in-select style of syntax since this will make it easier for me to generate the linq queries but I can't figure out why they are not compiling.
You can see some of the code I use to compile this snippet at the link on the top of this post.
Thanks!
Edit: Copying the code from the post I linked to:
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters cp = new CompilerParameters();
cp.GenerateInMemory = true;
cp.ReferencedAssemblies.Add("mscorlib.dll");
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Core.dll");
cp.ReferencedAssemblies.Add("System.Data.Linq.dll");
cp.ReferencedAssemblies.Add("System.Data.Entity.dll");
cp.ReferencedAssemblies.Add("MyApp.Data.dll");
var results = provider.CompileAssemblyFromSource(cp, source);
var assm = results.CompiledAssembly;
Edit2: As far as the exception goes, I get an exception on the second to last line of code (var results = ...). The exception is a BadImageFormatException:
Could not load file or assembly '0 bytes loaded from System,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or
one of its dependencies. An attempt was made to load a program with an
incorrect format
This seems to work for me:
static void Main(string[] args)
{
string sourceCode = #"namespace Dynamic {
using System.Linq;
using System.Collections.Generic;
public static class Query
{
public static int GetRecords()
{
MyApp.Data.DataMart container = new MyApp.Data.DataMart();
//return (container.EventDetails).Count();
return (from e in container.EventDetails select e).Count();
}
} }";
string sDynamDll = "Dynamic.dll";
string sDynamClass = "Query";
string sDynamMethod = "GetRecords";
System.CodeDom.Compiler.CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = false;
cp.GenerateInMemory = true;
cp.OutputAssembly = sDynamDll;
cp.ReferencedAssemblies.Add("mscorlib.dll");
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Core.dll");
cp.ReferencedAssemblies.Add("System.Data.Linq.dll");
cp.ReferencedAssemblies.Add("System.Data.Entity.dll");
cp.ReferencedAssemblies.Add("MyApp.Data.dll");
var providerOptions = new Dictionary<string, string>();
providerOptions.Add("CompilerVersion", "v4.0");
CodeDomProvider compiler = CodeDomProvider.CreateProvider("C#", providerOptions);
CompilerResults cr = compiler.CompileAssemblyFromSource(cp, sourceCode);
if (cr.Errors.HasErrors)
{
StringBuilder errors = new StringBuilder("Compiler Errors :\r\n");
foreach (CompilerError error in cr.Errors)
{
errors.AppendFormat("Line {0},{1}\t: {2}\n", error.Line, error.Column, error.ErrorText);
}
}
// verify assembly
Assembly theDllAssembly = null;
if (cp.GenerateInMemory)
theDllAssembly = cr.CompiledAssembly;
else
theDllAssembly = Assembly.LoadFrom(sDynamDll);
Type theClassType = theDllAssembly.GetType(sDynamClass);
foreach (Type type in theDllAssembly.GetTypes())
{
if (type.IsClass == true)
{
if (type.FullName.EndsWith("." + sDynamClass))
{
theClassType = type;
break;
}
}
}
// invoke the method
if (theClassType != null)
{
object[] method_args = new object[] { };
Object rslt = theClassType.InvokeMember(
sDynamMethod,
BindingFlags.Default | BindingFlags.InvokeMethod,
null,
null, // for static class
method_args);
Console.WriteLine("Results are: " + rslt.ToString());
}
Console.ReadKey();
}
You're probably getting BadImageFormatException because your code isn't actually compiling to a valid assembly. This might be because the old 2.0 compiler is used by default. Check the link below for enabling the C# the 3.5 version (I don't know if 4.0 is supported, but you don't need it):
http://blogs.msdn.com/b/lukeh/archive/2007/07/11/c-3-0-and-codedom.aspx
Also check the Errors collection on the CompilerResult that is returned from the CompileAssemblyFromSource() method. Failure to compile does not throw an exception, you must manually check for compile errors.
I didn't find an answer of how to get good exception information, however, I did solve this problem. The class library that contained the compiler code above was set to AnyCpu but the context it was running in under ASP.Net was x86. So this was causing it to fail when it tried to load System.dll since it was loading the wrong version (or something silly like that).
I'll be happy to give someone else the answer checkmark if you can (a) figure out how to get a real error message from this or (b) load the right reference type.

XNA C# Scripting with CSharpCodeProvider

I'm working on an RPG-style game in XNA and I'm working on implementing a scripting engine.
I've followed a few tutorials to try to get this working. Currently I read in the following from an XML file:
namespace MyGame
{
public class EngagedCode : ScriptingInterface.IScriptType1
{
public string RunScript()
{
ChangeFrame( 2 );
}
}
}
After I get that successfully into the project, I try to compile it with the following code:
Microsoft.CSharp.CSharpCodeProvider csProvider = new Microsoft.CSharp.CSharpCodeProvider();
CompilerParameters options = new CompilerParameters();
options.GenerateExecutable = false; //DLL
options.GenerateInMemory = true;
options.IncludeDebugInformation = true;
options.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
CompilerResults result = csProvider.CompileAssemblyFromSource(options, code);
However, at this point I always get the following error:
'result.CompiledAssembly' threw an exception of type 'System.IO.FileNotFoundException'
It seems as if the system is unable to find the .dll I've compiled, and I don't know why. I don't know how to get past this error. Does anybody have any suggestions?
Even if you generate it in memory it still writes a .dll to disk, unless you have compilation errors, and then you get this useless System.IO.FileNotFoundException. So most likely you have compile errors.
In order to pull those compile errors you need to add the below.
CompilerResults results = csProvider.CompileAssemblyFromSource(parameters, textBox1.Text);
if (results.Errors.Count > 0)
{
foreach (CompilerError CompErr in results.Errors)
{
//Hooray a list of compile errors
}
else
{
//Successful Compile
}
}
Also if you want to skip all this. Take a look at this class. It allows you just use the method body, this may not be sufficient for you though. Also you will need to change the namespace in the const CodeStart string.
The following line is not required:
options.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);

string contain math expression [duplicate]

I would like to do the equivalent of:
object result = Eval("1 + 3");
string now = Eval("System.DateTime.Now().ToString()") as string
Following Biri s link, I got this snippet (modified to remove obsolete method ICodeCompiler.CreateCompiler():
private object Eval(string sExpression)
{
CSharpCodeProvider c = new CSharpCodeProvider();
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("system.dll");
cp.CompilerOptions = "/t:library";
cp.GenerateInMemory = true;
StringBuilder sb = new StringBuilder("");
sb.Append("using System;\n");
sb.Append("namespace CSCodeEvaler{ \n");
sb.Append("public class CSCodeEvaler{ \n");
sb.Append("public object EvalCode(){\n");
sb.Append("return " + sExpression + "; \n");
sb.Append("} \n");
sb.Append("} \n");
sb.Append("}\n");
CompilerResults cr = c.CompileAssemblyFromSource(cp, sb.ToString());
if (cr.Errors.Count > 0)
{
throw new InvalidExpressionException(
string.Format("Error ({0}) evaluating: {1}",
cr.Errors[0].ErrorText, sExpression));
}
System.Reflection.Assembly a = cr.CompiledAssembly;
object o = a.CreateInstance("CSCodeEvaler.CSCodeEvaler");
Type t = o.GetType();
MethodInfo mi = t.GetMethod("EvalCode");
object s = mi.Invoke(o, null);
return s;
}
Old topic, but considering this is one of the first threads showing up when googling, here is an updated solution.
You can use Roslyn's new Scripting API to evaluate expressions.
If you are using NuGet, just add a dependency to Microsoft.CodeAnalysis.CSharp.Scripting.
To evaluate the examples you provided, it is as simple as:
var result = CSharpScript.EvaluateAsync("1 + 3").Result;
This obviously does not make use of the scripting engine's async capabilities.
You can also specify the evaluated result type as you intended:
var now = CSharpScript.EvaluateAsync<string>("System.DateTime.Now.ToString()").Result;
To evaluate more advanced code snippets, pass parameters, provide references, namespaces and whatnot, check the wiki linked above.
I have written an open source project, Dynamic Expresso, that can convert text expression written using a C# syntax into delegates (or expression tree). Text expressions are parsed and transformed into Expression Trees without using compilation or reflection.
You can write something like:
var interpreter = new Interpreter();
var result = interpreter.Eval("8 / 2 + 2");
or
var interpreter = new Interpreter()
.SetVariable("service", new ServiceExample());
string expression = "x > 4 ? service.aMethod() : service.AnotherMethod()";
Lambda parsedExpression = interpreter.Parse(expression,
new Parameter("x", typeof(int)));
parsedExpression.Invoke(5);
My work is based on Scott Gu article http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx .
If you specifically want to call into code and assemblies in your own project I would advocate using the C# CodeDom CodeProvider.
Here is a list of the most popular approaches that I am aware of for evaluating string expressions dynamically in C#.
Microsoft Solutions
C# CodeDom CodeProvider:
See How LINQ used to work and this CodeProject article
Roslyn:
See this article on Rosly Emit API and this StackOverflow answer
DataTable.Compute:
See this answer on StackOverflow
Webbrowser.Document.InvokeScript
See this StackOverflow question
DataBinder.Eval
ScriptControl
See this answer on StackOverflow and this question
Executing PowerShell:
See this CodeProject article
Non-Microsoft solutions (not that there is anything wrong with that)
Expression evaluation libraries:
Flee
DynamicExpresso
NCalc
CodingSeb.ExpressionEvaluator
Eval-Expression.NET
Javascript interpreter
Jint
To execute real C#
CS-Script
Roll your own a language building toolkit like:
Irony
Jigsaw
using System;
using Microsoft.JScript;
using Microsoft.JScript.Vsa;
using Convert = Microsoft.JScript.Convert;
namespace System
{
public class MathEvaluator : INeedEngine
{
private VsaEngine vsaEngine;
public virtual String Evaluate(string expr)
{
var engine = (INeedEngine)this;
var result = Eval.JScriptEvaluate(expr, engine.GetEngine());
return Convert.ToString(result, true);
}
VsaEngine INeedEngine.GetEngine()
{
vsaEngine = vsaEngine ?? VsaEngine.CreateEngineWithType(this.GetType().TypeHandle);
return vsaEngine;
}
void INeedEngine.SetEngine(VsaEngine engine)
{
vsaEngine = engine;
}
}
}
What are the performance implications of doing this?
We use a system based on something like the above mentioned, where each C# script is compiled to an in-memory assembly and executed in a separate AppDomain. There's no caching system yet, so the scripts are recompiled every time they run. I've done some simple testing and a very simple "Hello World" script compiles in about 0.7 seconds on my machine, including loading the script from disk. 0.7 seconds is fine for a scripting system, but might be too slow for responding to user input, in that case a dedicated parser/compiler like Flee might be better.
using System;
public class Test
{
static public void DoStuff( Scripting.IJob Job)
{
Console.WriteLine( "Heps" );
}
}
I have just written a similar library (Matheval) in pure C#.
It allows evaluating string and number expression like excel fomular.
using System;
using org.matheval;
public class Program
{
public static void Main()
{
Expression expression = new Expression("IF(time>8, (HOUR_SALARY*8) + (HOUR_SALARY*1.25*(time-8)), HOUR_SALARY*time)");
//bind variable
expression.Bind("HOUR_SALARY", 10);
expression.Bind("time", 9);
//eval
Decimal salary = expression.Eval<Decimal>();
Console.WriteLine(salary);
}
}
Looks like there is also a way of doing it using RegEx and XPathNavigator to evaluate the expression. I did not have the chance to test it yet but I kind of liked it because it did not require to compile code at runtime or use libraries that could not be available.
http://www.webtips.co.in/c/evaluate-function-in-c-net-as-eval-function-in-javascript.aspx
I'll try it and tell later if it worked. I also intend to try it in Silverlight, but it is too late and I'm almost asleep to do it now.
While C# doesn't have any support for an Eval method natively, I have a C# eval program that does allow for evaluating C# code. It provides for evaluating C# code at runtime and supports many C# statements. In fact, this code is usable within any .NET project, however, it is limited to using C# syntax. Have a look at my website, http://csharp-eval.com, for additional details.
There is a nice piece of code here
https://www.c-sharpcorner.com/article/codedom-calculator-evaluating-c-sharp-math-expressions-dynamica/
Download this and make it a class library which may be referenced in your project. This seems to be pretty fast and simple
Perhaps this could help !

How can I evaluate a C# expression dynamically?

I would like to do the equivalent of:
object result = Eval("1 + 3");
string now = Eval("System.DateTime.Now().ToString()") as string
Following Biri s link, I got this snippet (modified to remove obsolete method ICodeCompiler.CreateCompiler():
private object Eval(string sExpression)
{
CSharpCodeProvider c = new CSharpCodeProvider();
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("system.dll");
cp.CompilerOptions = "/t:library";
cp.GenerateInMemory = true;
StringBuilder sb = new StringBuilder("");
sb.Append("using System;\n");
sb.Append("namespace CSCodeEvaler{ \n");
sb.Append("public class CSCodeEvaler{ \n");
sb.Append("public object EvalCode(){\n");
sb.Append("return " + sExpression + "; \n");
sb.Append("} \n");
sb.Append("} \n");
sb.Append("}\n");
CompilerResults cr = c.CompileAssemblyFromSource(cp, sb.ToString());
if (cr.Errors.Count > 0)
{
throw new InvalidExpressionException(
string.Format("Error ({0}) evaluating: {1}",
cr.Errors[0].ErrorText, sExpression));
}
System.Reflection.Assembly a = cr.CompiledAssembly;
object o = a.CreateInstance("CSCodeEvaler.CSCodeEvaler");
Type t = o.GetType();
MethodInfo mi = t.GetMethod("EvalCode");
object s = mi.Invoke(o, null);
return s;
}
Old topic, but considering this is one of the first threads showing up when googling, here is an updated solution.
You can use Roslyn's new Scripting API to evaluate expressions.
If you are using NuGet, just add a dependency to Microsoft.CodeAnalysis.CSharp.Scripting.
To evaluate the examples you provided, it is as simple as:
var result = CSharpScript.EvaluateAsync("1 + 3").Result;
This obviously does not make use of the scripting engine's async capabilities.
You can also specify the evaluated result type as you intended:
var now = CSharpScript.EvaluateAsync<string>("System.DateTime.Now.ToString()").Result;
To evaluate more advanced code snippets, pass parameters, provide references, namespaces and whatnot, check the wiki linked above.
I have written an open source project, Dynamic Expresso, that can convert text expression written using a C# syntax into delegates (or expression tree). Text expressions are parsed and transformed into Expression Trees without using compilation or reflection.
You can write something like:
var interpreter = new Interpreter();
var result = interpreter.Eval("8 / 2 + 2");
or
var interpreter = new Interpreter()
.SetVariable("service", new ServiceExample());
string expression = "x > 4 ? service.aMethod() : service.AnotherMethod()";
Lambda parsedExpression = interpreter.Parse(expression,
new Parameter("x", typeof(int)));
parsedExpression.Invoke(5);
My work is based on Scott Gu article http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx .
If you specifically want to call into code and assemblies in your own project I would advocate using the C# CodeDom CodeProvider.
Here is a list of the most popular approaches that I am aware of for evaluating string expressions dynamically in C#.
Microsoft Solutions
C# CodeDom CodeProvider:
See How LINQ used to work and this CodeProject article
Roslyn:
See this article on Rosly Emit API and this StackOverflow answer
DataTable.Compute:
See this answer on StackOverflow
Webbrowser.Document.InvokeScript
See this StackOverflow question
DataBinder.Eval
ScriptControl
See this answer on StackOverflow and this question
Executing PowerShell:
See this CodeProject article
Non-Microsoft solutions (not that there is anything wrong with that)
Expression evaluation libraries:
Flee
DynamicExpresso
NCalc
CodingSeb.ExpressionEvaluator
Eval-Expression.NET
Javascript interpreter
Jint
To execute real C#
CS-Script
Roll your own a language building toolkit like:
Irony
Jigsaw
using System;
using Microsoft.JScript;
using Microsoft.JScript.Vsa;
using Convert = Microsoft.JScript.Convert;
namespace System
{
public class MathEvaluator : INeedEngine
{
private VsaEngine vsaEngine;
public virtual String Evaluate(string expr)
{
var engine = (INeedEngine)this;
var result = Eval.JScriptEvaluate(expr, engine.GetEngine());
return Convert.ToString(result, true);
}
VsaEngine INeedEngine.GetEngine()
{
vsaEngine = vsaEngine ?? VsaEngine.CreateEngineWithType(this.GetType().TypeHandle);
return vsaEngine;
}
void INeedEngine.SetEngine(VsaEngine engine)
{
vsaEngine = engine;
}
}
}
What are the performance implications of doing this?
We use a system based on something like the above mentioned, where each C# script is compiled to an in-memory assembly and executed in a separate AppDomain. There's no caching system yet, so the scripts are recompiled every time they run. I've done some simple testing and a very simple "Hello World" script compiles in about 0.7 seconds on my machine, including loading the script from disk. 0.7 seconds is fine for a scripting system, but might be too slow for responding to user input, in that case a dedicated parser/compiler like Flee might be better.
using System;
public class Test
{
static public void DoStuff( Scripting.IJob Job)
{
Console.WriteLine( "Heps" );
}
}
I have just written a similar library (Matheval) in pure C#.
It allows evaluating string and number expression like excel fomular.
using System;
using org.matheval;
public class Program
{
public static void Main()
{
Expression expression = new Expression("IF(time>8, (HOUR_SALARY*8) + (HOUR_SALARY*1.25*(time-8)), HOUR_SALARY*time)");
//bind variable
expression.Bind("HOUR_SALARY", 10);
expression.Bind("time", 9);
//eval
Decimal salary = expression.Eval<Decimal>();
Console.WriteLine(salary);
}
}
Looks like there is also a way of doing it using RegEx and XPathNavigator to evaluate the expression. I did not have the chance to test it yet but I kind of liked it because it did not require to compile code at runtime or use libraries that could not be available.
http://www.webtips.co.in/c/evaluate-function-in-c-net-as-eval-function-in-javascript.aspx
I'll try it and tell later if it worked. I also intend to try it in Silverlight, but it is too late and I'm almost asleep to do it now.
While C# doesn't have any support for an Eval method natively, I have a C# eval program that does allow for evaluating C# code. It provides for evaluating C# code at runtime and supports many C# statements. In fact, this code is usable within any .NET project, however, it is limited to using C# syntax. Have a look at my website, http://csharp-eval.com, for additional details.
There is a nice piece of code here
https://www.c-sharpcorner.com/article/codedom-calculator-evaluating-c-sharp-math-expressions-dynamica/
Download this and make it a class library which may be referenced in your project. This seems to be pretty fast and simple
Perhaps this could help !

Categories

Resources