/// <summary> /// Compile C# source code /// </summary> /// <param name="sourcePath">path to source</param> /// <param name="moreReferences">additional library references</param> /// <returns>compiled assembly</returns> public static Assembly CompileSource(string sourcePath, MetadataReference[] moreReferences = null) { string sourceText = File.ReadAllText(sourcePath); SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText( sourceText, path: sourcePath, encoding: System.Text.Encoding.UTF8); string assemblyName = Path.GetRandomFileName(); var assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location); MetadataReference[] references = new MetadataReference[] { //--- these can't be created any other way // https://stackoverflow.com/questions/23907305/roslyn-has-no-reference-to-system-runtime MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "mscorlib.dll")), MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.dll")), MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Core.dll")), MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Data.dll")), MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Collections.dll")), MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Runtime.dll")), //--- these are referenced by a type we need //MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(typeof(Object).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(typeof(System.Linq.Enumerable).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(typeof(TuringTrader.Simulator.Algorithm).GetTypeInfo().Assembly.Location), //MetadataReference.CreateFromFile(typeof(TuringTrader.Indicators.IndicatorsBasic).GetTypeInfo().Assembly.Location), //--- this is what we used with CodeDOM /* * cp.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location); * cp.ReferencedAssemblies.Add("System.dll"); * cp.ReferencedAssemblies.Add("System.Runtime.dll"); * cp.ReferencedAssemblies.Add("System.Collections.dll"); * cp.ReferencedAssemblies.Add("System.Core.dll"); * cp.ReferencedAssemblies.Add("System.Data.dll"); * cp.ReferencedAssemblies.Add("OxyPlot.dll"); * cp.ReferencedAssemblies.Add("OxyPlot.Wpf.dll"); */ }; if (moreReferences != null) { foreach (var r in moreReferences) { references = references.Append(r).ToArray(); } } CSharpCompilation compilation = CSharpCompilation.Create( assemblyName, syntaxTrees: new[] { syntaxTree }, references: references, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); using (var dll = new MemoryStream()) using (var pdb = new MemoryStream()) { EmitResult result = compilation.Emit(dll, pdb); if (!result.Success) { IEnumerable <Diagnostic> failures = result.Diagnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error); foreach (Diagnostic diagnostic in failures) { // find error location and line number int errorChar = diagnostic.Location.SourceSpan.Start; string errorSource = sourceText.Substring(0, errorChar); int lineNumber = errorSource.Split('\n').Length; Output.WriteLine("Line {0}: {1} - {2}", lineNumber, diagnostic.Id, diagnostic.GetMessage()); } } else { dll.Seek(0, SeekOrigin.Begin); pdb.Seek(0, SeekOrigin.Begin); Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(dll, pdb); return(assembly); } } return(null); }