1: public sealed class LambdaCompiler<T>
2: {
3: private Dictionary<string, T> _expressionCache;
4: private List<string> _compilerOutputs;
5:
6: public IList<string> LastCompilerOutputs
7: {
8: get { return _compilerOutputs; }
9: }
10:
11: public LambdaCompiler()
12: {
13: _expressionCache = new Dictionary<string, T>();
14: }
15:
16: private string GetTemplateClass(string expression)
17: {
18: if (!expression.EndsWith(";"))
19: expression += ";";
20:
21: StringBuilder sb = new StringBuilder();
22: sb.AppendLine("class ExpressionContainer {");
23: sb.AppendLine(" public " + GetNameFromType(typeof(T)) + " Expression {");
24: sb.AppendLine(" get { return " + expression + " } } }");
25: return sb.ToString();
26: }
27:
28: private string GetNameFromType(Type t)
29: {
30: if (t.IsGenericType)
31: {
32: string name = t.Name;
33: string displayName = t.Namespace + "." + name.Substring(0, name.IndexOf('`'));
34: string paramList = string.Join(",", (from a in t.GetGenericArguments() select a.FullName).ToArray());
35: return string.Format("{0}<{1}>", displayName, paramList);
36: }
37: return t.FullName;
38: }
39:
40: private IEnumerable<string> GetInMemoryAssemblies()
41: {
42: List<string> assemblies = new List<string>();
43: foreach (var alreadyInMemory in AppDomain.CurrentDomain.GetAssemblies())
44: {
45: try
46: {
47: assemblies.Add(alreadyInMemory.Location);
48: }
49: catch (Exception) { }
50: }
51: return assemblies;
52: }
53:
54: public T GetLambda(string lambdaText)
55: {
56: T lambda;
57: if (_expressionCache.TryGetValue(lambdaText, out lambda))
58: return lambda;
59:
60: try
61: {
62: Assembly compiledAssembly;
63: string source = GetTemplateClass(lambdaText);
64: using (CSharpCodeProvider provider = new CSharpCodeProvider())
65: {
66: var assemblies = GetInMemoryAssemblies();
67: var parameters = new CompilerParameters(assemblies.ToArray());
68: parameters.GenerateExecutable = false;
69: parameters.GenerateInMemory = true;
70:
71: CompilerResults results = provider.CompileAssemblyFromSource(parameters, source);
72:
73: if (results.Errors.HasErrors)
74: {
75: _compilerOutputs = results.Errors.OfType<CompilerError>().Select(s => s.ErrorText).ToList();
76: return default(T);
77: }
78:
79: compiledAssembly = results.CompiledAssembly;
80: _compilerOutputs = (from string s in results.Output select s).ToList();
81: }
82:
83: object o = compiledAssembly.CreateInstance("ExpressionContainer");
84: var expression = (T)o.GetType().GetProperty("Expression").GetValue(o, null);
85: if (expression == null)
86: {
87: _compilerOutputs.Add("Error: result is null instead of a type " + GetNameFromType(typeof(T)));
88: return default(T);
89: }
90:
91: _expressionCache.Add(lambdaText, expression);
92: return expression;
93: }
94: catch (Exception err)
95: {
96: _compilerOutputs = new List<string>() { err.ToString() };
97: return default(T);
98: }
99: }
100: }