Execution-Time Code Generation in C#: A Custom C# Class

The general solution has some loop overhead, and it’d be nice to get rid of this. To do this, you need a version of eval that evaluates an expression directly.

This example will generate a class that evaluates the polynomial in a single expression.

It will generate a class like this:

// Polynomial evaluator

// Evaluating Y = 5.5 + 7 X^1 + 15 X^2 + 30 X^3 + 500 X^4 + 100 X^5 + 1 X^6

public class Poly_1001 : PolyInterface.IPolynomial {

public double Eval(double x)

{

return (5.5

+ (x * (7

+ (x * (15

+ (x * (30

+ (x * (500

+ (x * (100

+ (x * (1 + 0)))))))))))));

}

}

The class to generate this file, compile it, and load it is as follows:

using System;

using System.IO;

using System.Diagnostics;

using System.Reflection;

class PolyCodeSlow: Polynomial

{

public PolyCodeSlow(params double[] coefficients): base(coefficients)

{

}

void WriteCode()

{

string timeString = polyNumber.ToString();

polyNumber++;

string filename = “PS_” + timeString;

Stream s = File.Open(filename + “.cs”, FileMode.Create);

StreamWriter t = new StreamWriter(s);

 

t.WriteLine(“// polynomial evaluator”);

t.Write(“// Evaluating y = “);

 

string[] terms = new string[coefficients.Length];

terms[0] = coefficients[0].ToString();

 

for (int i = 1; i < coefficients.Length; i++)

terms[i] = String.Format(“{0} X^{1}”, coefficients[l], i);

t.Write(“{0}”, String.Join(” + “, terms));

t.WriteLine();

 

t.WriteLine(“”);

 

string className = “Poly_” + timeString;

t.WriteLine(“class {0}”, className);

t.WriteLine(“{“);

t.WriteLine(“public double Eval(double value)”);

t.WriteLine(“{“);

t.WriteLine(” return(“);

t.WriteLine(“{0}”, coefficients[0]);

 

string closing = “”;

for (int i = 1; i < coefficients.Length; i++)

{

t.WriteLine(” + value * ({0} “, coefficients[i]);

closing += “)”;

}

t.Write(“\t{0}”, closing);

t.WriteLine(“);”);

t.WriteLine(“}”);

t.WriteLine(“}”);

t.Close();

s.Close();

//compile the DLL

CompilerParameters compParams = new CompilerParameters();

compParams.CompilerOptions = “/target:library /o+”;

compParams.ReferencedAssemblies.AddRange(new string[]

{Path.GetFileName(Assembly.GetExecutingAssembly().CodeBase),

“mscorlib.dll”,

“System.dll”});

compParams.IncludeDebugInformation = false;

compParams.GenerateInMemory = false;

compParams.OutputAssembly = (filename + “.dll”);

CompilerResults res = provider.CompileAssemblyFromFile(compParams,

filename + “.cs”);

// Open the file, and get a pointer to the method info

Assembly a = Assembly.LoadFrom(filename + “.dll”);

func = a.CreateInstance(className);

invokeType = a.GetType(className);

File.Delete(filename + “.cs”);

}

public override IPolynomial GetEvaluate()

{

return((IPolynomial) this);

}

public override double Evaluate(double value)

{

object[] args = new Object[] {value};

object retValue =

invokeType.InvokeMember(“Eval”,

BindingFlags.Default | BindingFlags.InvokeMethod,

null,

func,

args);

return((double) retValue);

}

object func = null;

Type invokeType = null;

static int polyNumber = 0;                     // which number we’re using…

}

The first time a polynomial is evaluated, the WriteCode() function writes the code out to the file and compiles it. It then uses Assembly.LoadFrom() to load the assembly and Activator.CreateInstance() to create an instance of the class. The instance and the type are then stored away for later use.

When it’s time to call the function, the value for x is put into an array, and Type.InvokeMember() is used to locate and call the function.

When this version is called, it generates the results shown in Table 32-2.

These aren’t exactly the results you want. The problem is that Type.MethodInvoke() is a general function and has a lot to do. It needs to locate the function based on the name and parameters and perform other operations, and it does this every time the function is called.

What’s needed is a way to perform the call without the overhead—in other words, a way to define the way a method will look without defining what class the method is in. That’s a perfect description of an interface.

Source: Gunnerson Eric, Wienholt Nick (2005), A Programmer’s Introduction to C# 2.0, Apress; 3rd edition.

Leave a Reply

Your email address will not be published. Required fields are marked *