12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 |
- using System;
- using System.CodeDom.Compiler;
- using System.Collections.Generic;
- using System.Linq;
- namespace FormulaEnginePoC.CSharpProvider
- {
- public class ExpressionCompiler<TDelegate> where TDelegate : Delegate
- {
- private readonly string _expressionCode;
- private readonly string _baseClass;
- private readonly List<string> _assemblies = new List<string>();
- private readonly List<string> _namespaces = new List<string>();
- private CodeCompiler<TDelegate> _codeCompiler;
- private TDelegate _compiledDelegate;
- public CompilerError[] CompilerErrors => _codeCompiler.CompilerErrors.ToArray();
- public TDelegate CompiledDelegate => _compiledDelegate ?? throw new InvalidOperationException("No compiled yet");
- public ExpressionCompiler(string expressionCode, string baseClass = null)
- {
- _expressionCode = expressionCode;
- _baseClass = baseClass;
- }
- public void AddReferenceAssembly(params string[] assemblies)
- {
- _assemblies.AddRange(assemblies);
- }
- public void AddNamespace(params string[] namespaces)
- {
- _namespaces.AddRange(namespaces);
- }
- public void Compile()
- {
- _codeCompiler = new CodeCompiler<TDelegate>();
- var namespaceIncluding = string.Join(Environment.NewLine, _namespaces.Select(p => $"using {p};"));
- var typeName = $"ClassOnTheFly_{string.Join("", Guid.NewGuid().ToByteArray().Select(p => $"{p:X2}"))}";
- var methodName = $"MethodOnTheFly_{string.Join("", Guid.NewGuid().ToByteArray().Select(p => $"{p:X2}"))}";
- var delegateMethod = typeof(TDelegate).GetMethod("Invoke") ?? throw new MissingMethodException("Can not find method `Invoke' from Delegate");
- var returnType = delegateMethod.ReturnType;
- var paramList = string.Join(",", delegateMethod.GetParameters().Select((p, i) => p.ParameterType.FullName + (i == 0 ? " p" : $" arg{i - 1}")));
- var preCompileCode =
- $"{namespaceIncluding}" +
- $"public class {typeName} {(string.IsNullOrWhiteSpace(_baseClass) ? "" : $":{_baseClass}")}" +
- $"{{ public static {returnType.FullName} {methodName}({paramList})" +
- $" {{" +
- $" return {_expressionCode};" +
- $" }}" +
- $"}}";
- _codeCompiler.Compile(typeName, methodName, preCompileCode, _assemblies.ToArray());
- _compiledDelegate = _codeCompiler.CompiledDelegate;
- }
- }
- }
|