In the DotNetYaml sample code I'm looking at, there's a C# construct:
var deserializer = new Deserializer(namingConvention: new CamelCaseNamingConvention());
var order = deserializer.Deserialize<Order>(input);
What is the equivalent F# code? I've tried
let deserializer = new Deserializer(namingConvention=new CamelCaseNamingConvention())
deserializer.Deserialize<Meta>(input)
If you have a C# library that defines optional parameters, then you can use the syntax you are using in your question. To quickly show that's the case, I compiled the following C# code as a library:
using System;
namespace Demo {
public class MyClass {
public static void Foo(int first, string second = "foo", string third = "bar") { }
}
}
You can reference this and use it from F# as follows:
open Demo
MyClass.Foo(1, third="hi")
I tried to do this with YamlDotNet which, I guess, is the library that you were using, but I get an error that the Deserializer class does not have namingConvention as an argument, so my guess would be that you are probably using a different version of the library than you are thinking (or perhaps, my guess of what library you're using was wrong...).
Related
Suppose my code possesses the knowledge about the metadata of a
nonexistent class library "mytest.dll", such as the types in this library, the functions of the types, the parameters and return types of the functions, etc.
How does my code manufacture this DLL using techniques such as reflection?
I know my code can generate the "mytest.cs" text file, then execute the compiler to produce the DLL, then delete the "mytest.cs" file. Just want to know if there are "more advanced" or "cooler" ways to do it.
Thanks.
There are 4 main steps in the process to compile and execute dynamic .net scripts from your application, even really complex scenarios can be simplified in this way:
Generate the code
Compile the script
Load the assembly
Execute the code
Lets generate a simple Hello Generated C# World App right now!:
Create a method that will generate an assembly that has 1 class called HelloWorldApp, this class has 1 method called GenerateMessage it will have X input parameters that will be integers, it will return a CSV string of the arguments that were passed in to it.
This solution requires the following package to be installed:
PM> Install-Package 'Microsoft.CodeAnalysis.CSharp.Scripting'
And will require the following using statements:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
Orchestration
The following method encapsulates the above steps:
private static void GenerateAndExecuteApp(int numberOfParameters)
{
string nameSpace = "Dynamic.Example";
string className = "HelloWorldApp";
string methodName = "GenerateMessage";
// 1. Generate the code
string script = BuildScript(nameSpace, className, methodName, numberOfParameters);
// 2. Compile the script
// 3. Load the Assembly
Assembly dynamicAssembly = CompileScript(script);
// 4. Execute the code
int[] arguments = Enumerable.Range(1, numberOfParameters).ToArray();
string message = ExecuteScript(dynamicAssembly, nameSpace, className, methodName, arguments);
Console.Out.WriteLine(message);
}
Generate the code
You say you already have item 1 sorted out, you can use StringBuilder, T4 templates or other mechanisms to generate the code files.
generating the code itself is its own question if you need help with that.
However, for our demo app, the following would work:
private static string BuildScript(string nameSpace, string className, string methodName, int numberOfParameters)
{
StringBuilder code = new StringBuilder();
code.AppendLine("using System;");
code.AppendLine("using System.Linq;");
code.AppendLine();
code.AppendLine($"namespace {nameSpace}");
code.AppendLine("{");
code.AppendLine($" public class {className}");
code.AppendLine(" {");
var parameterNames = Enumerable.Range(0, numberOfParameters).Select(x => $"p{x}").ToList();
code.Append($" public string {methodName}(");
code.Append(String.Join(",", parameterNames.Select(x => $"int {x}")));
code.AppendLine(")");
code.AppendLine(" {");
code.Append(" return $\"");
code.Append(String.Join(",", parameterNames.Select(x => $"{x}={{{x}}}")));
code.AppendLine("\";");
code.AppendLine(" }");
code.AppendLine(" }");
code.AppendLine("}");
return code.ToString();
}
For an input value of 3, the following code is generated:
using System;
using System.Linq;
namespace Dynamic.Example
{
public class HelloWorldApp
{
public string GenerateMessage(int p0,int p1,int p2)
{
return $"p0={p0},p1={p1},p2={p2}";
}
}
}
Compile the script (and Load it)
These are two discrete steps, however it is easiest to code them together in the same method, for this example we will ignore the generated dll and load the assembly directly into memory, that is generally the more likely use case for this type of scripting scenario anyway.
The hardest element of this is usually the referencing of the relevant dlls. There are a number of ways to achieve this, including loading all the dlls that are in the current executing context, I find a simple way to do this is to access the Assembly reference from the Type reference for the types we want to use inside the dynamic script:
List<string> dlls = new List<string> {
typeof(object).Assembly.Location,
typeof(Enumerable).Assembly.Location
};
Cut a long story short, this method compiles and loads the assembly into memory. It includes some crude compilation error handling, just to demonstrate how to do it:
private static Assembly CompileScript(string script)
{
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(script);
// use "mytest.dll" if you want, random works well enough
string assemblyName = System.IO.Path.GetRandomFileName();
List<string> dlls = new List<string> {
typeof(object).Assembly.Location,
typeof(Enumerable).Assembly.Location
};
MetadataReference[] references = dlls.Distinct().Select(x => MetadataReference.CreateFromFile(x)).ToArray();
CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName,
syntaxTrees: new[] { syntaxTree },
references: references,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
// Now we actually compile the script, this includes some very crude error handling, just to show you can
using (var ms = new MemoryStream())
{
EmitResult result = compilation.Emit(ms);
if (!result.Success)
{
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
List<string> errors = new List<string>();
foreach (Diagnostic diagnostic in failures)
{
//errors.AddDistinct(String.Format("{0} : {1}", diagnostic.Id, diagnostic.Location, diagnostic.GetMessage()));
errors.Add(diagnostic.ToString());
}
throw new ApplicationException("Compilation Errors: " + String.Join(Environment.NewLine, errors));
}
else
{
ms.Seek(0, SeekOrigin.Begin);
return Assembly.Load(ms.ToArray());
}
}
}
Execute the code
Finally, we can use reflection to instantiate an instance of the new app and then we can obtain a reference to the method and it. The name of the parameters is irrelevant, as long
we pass them through in the correct order:
for this demo the order is sort of irrelevant to, given they are all the same type ;)
private static string ExecuteScript(Assembly assembly, string nameSpace, string className, string methodName, int[] arguments)
{
var appType = assembly.GetType($"{nameSpace}.{className}");
object app = Activator.CreateInstance(appType);
MethodInfo method = appType.GetMethod(methodName);
object result = method.Invoke(app, arguments.Cast<object>().ToArray());
return result as string;
}
Output
The final output from all this for our method with 3 passed into it is:
p0=1,p1=2,p2=3
So that was super crude, you can bypass most of the indirect reflection aspects through the use of Interfaces. If your generated script inherits from types or interfaces that the calling code also has a strong reference to, then ExecuteScript in the above example might look like this:
private static string ExecuteScript(Assembly assembly, string nameSpace, string className)
{
var appType = assembly.GetType($"{nameSpace}.{className}");
object app = Activator.CreateInstance(appType);
if (app is KnownInterface known)
{
return known.GenerateMessage(1,2,3);
}
throw new NotSupportedException("Couldn't resolve known type");
}
The major benefit to using an interface or base class reference is that you can natively set properties or call other methods without having to reflect references to them all or to resort to using dynamic which would work, but becomes a bit harder to debug.
Of course the interface solution is hard to implement when we had a variable number of parameters, so that's not the best example, usually with dynamic scripts you would construct a known environment, say a known class and methods, but you might want to inject custom code into the body of the method.
It's a bit of fun in the end, but this simple example shows that C# can be used as a runtime scripting engine without too much trouble.
I am trying to directly invoke IronPython's built-in modules from C#. It looks like I'm missing some important initialization, that I can't find anywhere in the code.
Here's what I do:
namespace py.consoleio
{
using IronPython.Runtime;
using Microsoft.Scripting.Hosting;
using Microsoft.Scripting.Hosting.Providers;
using Microsoft.Scripting.Runtime;
public static class consoleio
{
public static string name;
static void Main()
{
var setup = new ScriptRuntimeSetup();
setup.LanguageSetups.Add(
IronPython.Hosting.Python.CreateLanguageSetup(null));
var dlrRuntime = new ScriptRuntime(setup);
var scriptDomainManager = HostingHelpers.GetDomainManager(dlrRuntime);
var pythonContext = new PythonContext(scriptDomainManager, null);
var context = new CodeContext(new PythonDictionary(), new ModuleContext(new PythonDictionary(), DefaultContext.DefaultPythonContext));
name = IronPython.Modules.Builtin.input(context, "What is your name?\n");
IronPython.Modules.Builtin.print(context, "Hi, %s.", consoleio.name);
System.GC.KeepAlive(pythonContext);
}
}
}
That properly outputs "What is your name?", but then crashes trying to decode input: unknown encoding: cp437.
Now I've already found, that encodings are initialized in Src/StdLib/Lib/encodings/init.py
I can't find how it gets to loading this module in a normal IronPython run (e.g. a console host), so I can't reproduce it in C# program.
My goal here is to invoke IronPython functions without dynamic dispatch.
UPD. Now I also tried to do this:
var engine = Python.CreateEngine();
this.ScriptDomainManager = HostingHelpers.GetDomainManager(engine.Runtime);
to the same result
Figured that one out: encodings module is implemented in Python in IronPython (core modules are in C#). It always worked with IronPythonConsole project, because it implicitly adds IronPython source for standard libraries to Python path. I just had to explicitly specify path like this:
var options = new Dictionary<string, object> { ["SearchPaths"] = path };
var engine = Python.CreateEngine(options);
I Know I'm able to pipe out/in using simple Console.WriteLine and Console.ReadLine methods, but that way I'm passing a string between processes (which must be parsed to recreate the object).
What I'm wondering is if I would be able to pipe my own types, so that I could retrieve them easily in destiny process. What I expect is to do something like:
myProgram | get-member
And the output would something like MyNameSpace.MyType and the list of its members (currently it shows the typeName System.String)
Is that possible in a console app or could I only achieve this using cmdlets?
The easiest way to do this is to use serialization to turn the objects you wish to send from one to the other into a pipeable format to send them from one to the other. There are, however, a number of constraints on doing this:
First, the implementation of the types you're passing back and forth have to be available to all the apps that may handle them. (That's not a problem for PowerShell because all the cmdlets run inside the same process.) So the easiest way to do this is to create the types you're going to pipe around inside a class library that's referenced by all the console apps. This class, for example, I put in my sample shared library:
[Serializable]
public class TestClass
{
public string Test { get; set; }
public string TestAgain { get; set; }
public string Cheese { get; set; }
}
The [Serializable] attribute marks it as serializable, which is sufficient for simple classes. For more complex classes, more may be required - see MSDN, starting here: http://msdn.microsoft.com/en-us/library/4abbf6k0(v=VS.71).aspx
Then, in the program you're piping from, you serialize it to XML and write it out to console like this:
using System;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using Shared;
namespace Out
{
class Program
{
static void Main(string[] args)
{
// Create the object.
TestClass test = new TestClass();
test.Test = "Monkey";
test.TestAgain = "Hat";
test.Cheese = "Fish";
// Serialize it.
XmlSerializer serializer = new XmlSerializer(typeof (TestClass));
StringBuilder sb = new StringBuilder();
using (var writer = new StringWriter(sb))
serializer.Serialize(writer, test);
// And write it to console.
Console.WriteLine(sb.ToString());
}
}
}
When run, this outputs the instance's properties encoded in XML, thus:
<?xml version="1.0" encoding="utf-16"?>
<TestClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http
://www.w3.org/2001/XMLSchema">
<Test>Monkey</Test>
<TestAgain>Hat</TestAgain>
<Cheese>Fish</Cheese>
</TestClass>
Then, in your receiving application, you reverse the process, reading from the console, thus:
using System;
using System.IO;
using System.Xml.Serialization;
using Shared;
namespace In
{
class Program
{
static void Main(string[] args)
{
// Read the input XML; until complete.
string input = Console.In.ReadToEnd();
TestClass passedIn;
// Deserialize it.
var serializer = new XmlSerializer(typeof (TestClass));
using (var reader = new StringReader(input))
passedIn = (TestClass) serializer.Deserialize(reader);
// Do something with the object.
Console.WriteLine("Test: {0}", passedIn.Test);
Console.WriteLine("TestAgain: {0}", passedIn.TestAgain);
Console.WriteLine("Cheese: {0}", passedIn.Cheese);
}
}
}
And voila!
C:\Working\PipeExample\In\bin\Debug>..\..\..\Out\bin\Debug\Out.exe | in
Test: Monkey
TestAgain: Hat
Cheese: Fish
You'll need some additional code, of course, to make sure that the receiving application knows what type(s) to expect - or can handle anything it gets - and since the intermediate XML is not very human-parsable, you'll need a way to make sure that the sending application knows when it's talking to a pipe and when it's talking to a human. In .NET 4.5, the Console.IsOutputRedirected() method will do that for you ( http://msdn.microsoft.com/en-us/library/system.console.isoutputredirected%28v=VS.110%29.aspx ), but in earlier versions, there's not an easy way to get at this information programmatically.
But this is the core of the thing, and looking at the documentation for and around XmlSerializer should give you the rest.
Why don't you write your own cmdlet instead of a console program?
A PowerShell module can be a binary module (a DLL assembly) composed by cmdlets writen in C#. Have a look to Installing the Windows PowerShell SDK.
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 !
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 !