patterncsharpMinor
Evaluating algebra expression using an auxiliary VB class compiled on the fly and consumed in a C# project
Viewed 0 times
expressiontheclasscompiledconsumedprojectusingandalgebraevaluating
Problem
-
I want to create algebra evaluator but I don't want to write my own parser because it takes much time to learn.
-
I don't like algebra expression in C# because it does not look natural compared to VB counterpart. For example, "x^2+1" in VB must be written as "Math.Pow(x,2)+1" in C#.
-
I am still a newbie in the world of programming and always interested to learn the best practices. I am always not confident with my code.
Minimal Working Example
Based on the 3 constraint given above, I tried to implement it as follows.
First, I create a template named
where
Second, I create a class named
```
using Microsoft.VisualBasic;
using System;
using System.CodeDom.Compiler;
using System.IO;
using System.Reflection;
using System.Text;
namespace Mathematics
{
public static class Parser
{
static string expression;
static object obj;
static MethodInfo mi;
public static string Expression
{
get
{
return expression;
}
set
{
expression = value;
string source;
using (StreamReader sr = new StreamReader("template.vb"))
{
source = sr.ReadToEnd().Replace("expression-in-x", expression);
}
CompilerParameters cps = new CompilerParameters();
cps.GenerateExecutable = false;
cps.GenerateInMemory = true;
CompilerResults crs = (new VBCodeProvider()).CompileAssemblyFromSource(cps, source);
if (crs
I want to create algebra evaluator but I don't want to write my own parser because it takes much time to learn.
-
I don't like algebra expression in C# because it does not look natural compared to VB counterpart. For example, "x^2+1" in VB must be written as "Math.Pow(x,2)+1" in C#.
-
I am still a newbie in the world of programming and always interested to learn the best practices. I am always not confident with my code.
Minimal Working Example
Based on the 3 constraint given above, I tried to implement it as follows.
First, I create a template named
template.vb as follows:Imports System
Imports System.Math
Namespace AnyNamespace
Public Class AnyClass
Public Function AnyMethod(ByVal x As Double) As Double
Return expression-in-x
End Function
End Class
End Namespacewhere
expression-in-x is just a place holder that will be replaced. See the next code how I replace it.Second, I create a class named
Parser.cs as follows:```
using Microsoft.VisualBasic;
using System;
using System.CodeDom.Compiler;
using System.IO;
using System.Reflection;
using System.Text;
namespace Mathematics
{
public static class Parser
{
static string expression;
static object obj;
static MethodInfo mi;
public static string Expression
{
get
{
return expression;
}
set
{
expression = value;
string source;
using (StreamReader sr = new StreamReader("template.vb"))
{
source = sr.ReadToEnd().Replace("expression-in-x", expression);
}
CompilerParameters cps = new CompilerParameters();
cps.GenerateExecutable = false;
cps.GenerateInMemory = true;
CompilerResults crs = (new VBCodeProvider()).CompileAssemblyFromSource(cps, source);
if (crs
Solution
public static class ParserWhy is this class static? When you have a class with some state, you should almost never make that state static. For example, you might be very surprised when you try using this code from multiple threads.
using (StreamReader sr = new StreamReader("template.vb"))
{
source = sr.ReadToEnd().Replace("expression-in-x", expression);
}You could have used
File.ReadAllText() to make this simpler.CompilerParameters cps = new CompilerParameters();
cps.GenerateExecutable = false;
cps.GenerateInMemory = true;Using
var and object initializer, you can shorten this to:var cps = new CompilerParameters { GenerateExecutable = false, GenerateInMemory = true };Also,
cps is not a great name, don't shorten names unnecessarily.obj = a.CreateInstance("AnyNamespace.AnyClass");
mi = obj.GetType().GetMethod("AnyMethod");Instead of object and
MethodInfo, you could store the method as a delegate:Func compiledFunction;
…
var obj = a.CreateInstance("AnyNamespace.AnyClass");
var mi = obj.GetType().GetMethod("AnyMethod");
compiledFunction =
(Func)Delegate.CreateDelegate(typeof(Func), obj, mi);
…
return compiledFunction(x);As another advantage, this is likely going to be faster, since it's not using reflection for every invocation of
Evaluate().Code Snippets
public static class Parserusing (StreamReader sr = new StreamReader("template.vb"))
{
source = sr.ReadToEnd().Replace("expression-in-x", expression);
}CompilerParameters cps = new CompilerParameters();
cps.GenerateExecutable = false;
cps.GenerateInMemory = true;var cps = new CompilerParameters { GenerateExecutable = false, GenerateInMemory = true };obj = a.CreateInstance("AnyNamespace.AnyClass");
mi = obj.GetType().GetMethod("AnyMethod");Context
StackExchange Code Review Q#60743, answer score: 4
Revisions (0)
No revisions yet.