Compile Lambda or Code String to MethodInfo or Action or Func:
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace CodeCompiler
{
public class CompilationException : Exception
{
public List<CompilerError> Errors { get; private set; }
public CompilationException(CompilerErrorCollection errors) : base("Error compiling expression")
{
Errors = new List<CompilerError>();
foreach (CompilerError error in errors)
Errors.Add(error);
}
}
public class Compiler
{
public List<string> ReferenceDLLs { get; private set; }
public List<Assembly> ReferenceAssemblies { get; private set; }
public Compiler()
{
ReferenceDLLs = new List<string> { "System.dll", "System.Core.dll", "System.Data.dll", "System.Data.DataSetExtensions.dll", "System.Xml.dll", "System.Xml.Linq.dll" };
//ReferenceDLLs = AppDomain.CurrentDomain.GetAssemblies().Where(x => !x.IsDynamic).Select(x => x.Location).ToList();
ReferenceAssemblies = new List<Assembly>();
}
public Assembly CompileCSFile(string csFilePath)
{
using (StreamReader reader = new StreamReader(csFilePath))
return compileString(reader.ReadToEnd());
}
private MethodInfo compileStringToMethodInfo(string code)
{
Assembly assembly = compileString(code);
return assembly.GetType("FakeNamespace.FakeClass").GetMethod("MethodResult", BindingFlags.Static | BindingFlags.Public);
}
private Assembly compileString(string code)
{
CodeDomProvider compiler = CodeDomProvider.CreateProvider("CSharp");
CompilerResults result = compiler.CompileAssemblyFromSource(new CompilerParameters(ReferenceDLLs.Union(ReferenceAssemblies.ConvertAll(x => x.Location)).ToArray()), code);
if (result.Errors.Count > 0)
throw new CompilationException(result.Errors);
return result.CompiledAssembly;
}
private List<string> defaultUsingStatements()
{
return new List<string>()
{
"using System;",
"using System.Collections.Generic;",
"using System.Linq;",
"using System.IO;"
};
}
private string surroundLambaWithFakeClass<X, Y>(string text, List<string> usingStatements = null)
{
usingStatements = usingStatements ?? defaultUsingStatements();
string code = usingStatements.Aggregate((x, y) => x + "\r\n" + y) + @"
namespace FakeNamespace
{
public class FakeClass
{
public static CLASS2 MethodResult(CLASS1 param1)
{
Func<CLASS1, CLASS2> lambda = " + text + @";
return lambda(param1);
}
}
}";
code = code.Replace("CLASS1", typeof(X).ToString()).Replace("CLASS2", typeof(Y).ToString()).Replace("`1[", "<").Replace("]", ">");
return code;
}
private string surroundLambaWithFakeClass<X>(string text, List<string> usingStatements = null)
{
usingStatements = usingStatements ?? defaultUsingStatements();
string code = usingStatements.Aggregate((x, y) => x + "\r\n" + y) + @"
namespace FakeNamespace
{
public class FakeClass
{
public static void MethodResult(CLASS1 param1)
{
Action<CLASS1> lambda = " + text + @";
return lambda(param1);
}
}
}";
code = code.Replace("CLASS1", typeof(X).ToString()).Replace("`1[", "<").Replace("]", ">");
return code;
}
private string surroundMethodWithFakeClass<X>(string text, List<string> usingStatements = null)
{
usingStatements = usingStatements ?? defaultUsingStatements();
string code = usingStatements.Aggregate((x, y) => x + "\r\n" + y) + @"
namespace FakeNamespace
{
public class FakeClass
{
public static void MethodResult(CLASS1 param1)
{
" + text + @"
}
}
}";
code = code.Replace("CLASS1", typeof(X).ToString()).Replace("`1[", "<").Replace("]", ">");
return code;
}
private string surroundMethodWithFakeClass<X, Y>(string text, List<string> usingStatements = null)
{
usingStatements = usingStatements ?? defaultUsingStatements();
string code = usingStatements.Aggregate((x, y) => x + "\r\n" + y) + @"
namespace FakeNamespace
{
public class FakeClass
{
public static CLASS2 MethodResult(CLASS1 param1)
{
" + text + @"
}
}
}";
code = code.Replace("CLASS1", typeof(X).ToString()).Replace("CLASS2", typeof(Y).ToString()).Replace("`1[", "<").Replace("]", ">");
return code;
}
public Func<X, Y> ConvertMethodStringToMethodInfo<X, Y>(string text, List<string> usingStatements = null)
{
string code = surroundMethodWithFakeClass<X, Y>(text, usingStatements);
MethodInfo method = compileStringToMethodInfo(code);
return x => (Y)method.Invoke(null, new object[] { x });
}
public Action<X> ConvertMethodStringToMethodInfo<X>(string text, List<string> usingStatements = null)
{
string code = surroundMethodWithFakeClass<X>(text, usingStatements);
MethodInfo method = compileStringToMethodInfo(code);
return x => method.Invoke(null, new object[] { x });
}
public Func<X, Y> ConvertLambaStringToMethodInfo<X, Y>(string text, List<string> usingStatements = null)
{
string code = surroundLambaWithFakeClass<X, Y>(text, usingStatements);
MethodInfo methodInfo = compileStringToMethodInfo(code);
Func<X, Y> result = x => (Y)methodInfo.Invoke(null, new object[] { x });
return result;
}
public Action<X> ConvertLambaStringToMethodInfo<X>(string text, List<string> usingStatements = null)
{
string code = surroundLambaWithFakeClass<X>(text, usingStatements);
MethodInfo methodInfo = compileStringToMethodInfo(code);
return x => methodInfo.Invoke(null, new object[] { x });
}
public static string EscapeToProtectFromCodeInjection(string searchText)
{
return "\"" + searchText.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"";
}
}
}
Here's how to use it:
Func<string, IEnumerable<string>> stringSplitFunction = Compiler.ConvertLambaStringToMethodInfo<String, IEnumerable<String>>("x => x.Split(new string[] { \",\" }, StringSplitOptions.RemoveEmptyEntries).AsEnumerable()");
IEnumerable<string> result = stringSplitFunction("val1,val2");