HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Evaluating algebra expression using an auxiliary VB class compiled on the fly and consumed in a C# project

Submitted by: @import:stackexchange-codereview··
0
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 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 Namespace


where 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 Parser


Why 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 Parser
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;
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.