using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; namespace RaisingStudio { public static class EvaluatorExtension { private static Mono.CSharp.Evaluator evaluator; public static Mono.CSharp.Evaluator Evaluator { get { if (evaluator == null) { evaluator = new Mono.CSharp.Evaluator(new Mono.CSharp.CompilerSettings(), new Mono.CSharp.Report(new Mono.CSharp.ConsoleReportPrinter())); } return evaluator; } } private static string GetTypeDeclaration(Type type, List assemblyList) { if (!assemblyList.Contains(type.Assembly)) { assemblyList.Add(type.Assembly); } Assembly[] assemblies; string typeDeclaration = GetTypeDeclaration(type, out assemblies); if (assemblies != null) { assemblyList.AddRange(assemblies.Where(assembly => !assemblyList.Contains(assembly))); } return typeDeclaration; } public static string GetTypeDeclaration(Type type, out Assembly[] assemblies) { var assemblyList = new List(); assemblyList.Add(type.Assembly); if (type.IsGenericTypeDefinition || type.IsGenericType) { StringBuilder typeDeclaration = new StringBuilder(); int index = type.FullName.IndexOf('`'); typeDeclaration.Append(index > 0 ? type.FullName.Substring(0, index) : type.FullName); Type[] genericArguments = type.GetGenericArguments(); if (genericArguments.Length > 0) { typeDeclaration.Append('<'); typeDeclaration.Append(GetTypeDeclaration(genericArguments[0], assemblyList)); for (int i = 1; i < genericArguments.Length; i++) { typeDeclaration.Append(", "); typeDeclaration.Append(GetTypeDeclaration(genericArguments[i], assemblyList)); } typeDeclaration.Append('>'); } assemblies = assemblyList.ToArray(); return typeDeclaration.ToString(); } else { assemblies = assemblyList.ToArray(); return type.FullName; } } private static string GetDelegateDeclaration(string delegateType, IEnumerable parameters, out string[] parameterNames, out Assembly[] assemblies) { var assemblyList = new List(); var parameterNameList = new List(); StringBuilder delegateDeclaration = new StringBuilder(); delegateDeclaration.Append(delegateType); if ((parameters != null) && (parameters.Count() > 0)) { delegateDeclaration.Append('<'); int index = 0; foreach (var parameter in parameters) { Type parameterType = parameter.Type; if (index > 0) { delegateDeclaration.Append(", "); } delegateDeclaration.Append(GetTypeDeclaration(parameterType, assemblyList)); parameterNameList.Add(parameter.Name); index++; } delegateDeclaration.Append('>'); } parameterNames = parameterNameList.ToArray(); assemblies = assemblyList.ToArray(); return delegateDeclaration.ToString(); } private static string GetActionDeclaration(IEnumerable parameters, out string[] parameterNames, out Assembly[] assemblies) { return GetDelegateDeclaration("System.Action", parameters, out parameterNames, out assemblies); } private static string GetFuncDeclaration(IEnumerable parameters, out string[] parameterNames, out Assembly[] assemblies) { return GetDelegateDeclaration("System.Func", parameters, out parameterNames, out assemblies); } public static void AddReference(this Mono.CSharp.Evaluator evaluator, Assembly[] assemblies) { if (assemblies != null) { foreach (var assembly in assemblies) { if (assembly != typeof(object).Assembly) { evaluator.ReferenceAssembly(assembly); } } } } public static TDelegate Compile(this Mono.CSharp.Evaluator evaluator, string body) { Assembly[] assemblies; string code = string.Format("new {0}({1});", GetTypeDeclaration(typeof(TDelegate), out assemblies), body); AddReference(evaluator, assemblies); return (TDelegate)evaluator.Evaluate(code); } public static TDelegate Compile(this Mono.CSharp.Evaluator evaluator, IEnumerable parameters, string body) { return Compile(evaluator, body, parameters); } public static TDelegate Compile(this Mono.CSharp.Evaluator evaluator, string body, IEnumerable parameters) { Assembly[] assemblies; string code = string.Format("new {0}(({1}) => {{ {2} }});", GetTypeDeclaration(typeof(TDelegate), out assemblies), string.Join(", ", parameters), body); AddReference(evaluator, assemblies); return (TDelegate)evaluator.Evaluate(code); } public static Delegate CompileAction(this Mono.CSharp.Evaluator evaluator, string body, IEnumerable parameters) { string[] parameterNames; Assembly[] assemblies; string actionDeclaration = GetActionDeclaration(parameters, out parameterNames, out assemblies); string code = string.Format("new {0}(({1}) => {{ {2} }});", actionDeclaration, string.Join(", ", parameterNames), body); AddReference(evaluator, assemblies); return (Delegate)evaluator.Evaluate(code); } public static Delegate CompileFunc(this Mono.CSharp.Evaluator evaluator, string body, IEnumerable parameters) { if ((parameters == null) || (parameters.Count() < 1)) { throw new ArgumentException("parameters are required.", "parameters"); } string[] parameterNames; Assembly[] assemblies; string fucnDeclaration = GetFuncDeclaration(parameters, out parameterNames, out assemblies); string code = string.Format("new {0}(({1}) => {{ {2} }});", fucnDeclaration, string.Join(", ", parameterNames.Take(parameterNames.Length - 1)), body); AddReference(evaluator, assemblies); return (Delegate)evaluator.Evaluate(code); } } }