In order to compile a snip of codes dynamically, I need to define a template in the class of ExpressionEvaluation so that it can be used as a base. The template contains several parameters which will be replaced (such as a class name, a data type and an expression). I defined a string with parameters enclosed by {} so that those parameters can be easily replaced by dynamic values (string.Format(template, parameters...)).
Here is the template of snip codes in the class:
using System;
using System.Reflection;
using System.CodeDom;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
public class ExpressEvaluation { // class name
private const string _InitalizeValueCode = "private {0} _value = {1};"; // valType, valExp
private const string _ClassName = "_CalculatorWithFormula"; // 0
private const string _MethodAnswer = "Answer"; // 1
private const string _SourceCodeTemplate = @"
using System;
public class {} {{ // {{0}} Class name
{2}
public {} {1}() // {{1}} method to be called to get result
{{
return _value;
}}
}}";
public int GetAnswer() // method to get result as type
{
return _value;
}
}
The key methods in the class are BuildCodes() and GetAnswerByBuildAndRunCodes():
private static string BuildCodes(
string valueExp,
string varType)
{
string initializeValueCodes = string.Format(
_InitalizeValueCode, varType, valueExp);
string codes = string.Format(_SourceCodeTemplate,
_ClassName, _MethodAnswer, initializeValueCodes, varType);
return codes;
}
private static T GetAnswserByBuildAndRunCodes<T>(
string sourceCodes) where T : struct
{
object value = default(T);
CompilerResults cr = GetCompiler(sourceCodes);
var instance = cr.CompiledAssembly.CreateInstance(_ClassName);
Type type = instance.GetType();
MethodInfo m = type.GetMethod(_MethodAnswer);
value = m.Invoke(instance, null);
return (T)value;
}
Those two methods are very straightforward. In GetAnswserByBuildAndRunCodes(), a method GetCompiler() is called to get a C# CompilerResults object in the current context:
private static CompilerResults GetCompiler(string codes)
{
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;
parameters.IncludeDebugInformation = false;
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
{
parameters.ReferencedAssemblies.Add(asm.Location);
}
return codeProvider.CompileAssemblyFromSource(parameters, codes);
}
Here is the complete source codes for download.
0 comments:
Post a Comment