Simple Dynamic C# Execution
A simple way to execute C# code, without using the Visual Studio is shown in
RunCS.cs.
Steps:
- Compile the code as RunCS.exe;
- Create a CS file;
- Execute RunCS.exe "my_file.cs" param1 param2
The CS file must contain the following lines, as in
Program.cscript.
RunCS.cs
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Reflection;
namespace RunCS
{
static class RunCS
{
static void Assert(bool condition, string code, string message)
{
if (condition) return;
Console.WriteLine("FATAL: " + code + " - " + message);
Environment.Exit(1);
}
[STAThread]
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("Usage: RunCS <file.cs> [<params>]");
Console.WriteLine("Version v1209141124");
Console.WriteLine("//@title <application_title>");
Console.WriteLine("//@include <other_CS_file>");
Console.WriteLine("//@assembly <%ProgramFiles%\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.0\\System.dll>");
Console.WriteLine("//@main <namespace_name>.<class_name>");
args=new string[]{"C:\\Users\\Sorescud\\Desktop\\ROOT\\bin\\New Text Document.cs"};
}
Assert(System.IO.File.Exists(args[0]), "e1204141741", "File '" + args[0] + "' does not exist");
var directives = new Dictionary<string, List<string>>();
directives.Add("include", new List<string>() { args[0] });
foreach (string line in System.IO.File.ReadAllLines(args[0]))
{
string directive = line.Trim();
if (!directive.StartsWith("//@"))
continue;
directive = directive.Substring(3);
int length = directive.IndexOf(' ');
string directiveName = directive.Substring(0, length).ToLower();
string directiveValue = directive.Substring(length).Trim();
if(!directives.ContainsKey(directiveName))
directives.Add(directiveName, new List<string>());
directives[directiveName].Add(directiveValue);
}
Assembly compiledScript = CompileCode(directives);
if (directives.ContainsKey("title"))
Console.Title = directives["title"][0];
string[] parameters = new string[args.Length - 1];
for (var i = 1; i < args.Length; i++)
parameters[i - 1] = args[i];
Assert(compiledScript != null, "e1204141028", "Application not compiled properly.");
Assert(directives.ContainsKey("main"), "e1209141059", "//@main <ClassName> not defined!");
Assert(directives["main"].Count == 1, "e1209141100", "//@main <ClassName> must be defined only once!");
var entryClass = directives["main"][0];
Type mainType = getMainType(compiledScript, entryClass);
Assert(mainType != null, "e1204141029", " - Type " + entryClass + " could not be found");
var mainMethod = mainType.GetMethod("Main");
Assert(mainMethod != null, "e1204141030", "Main Method 'Main' not found in class " + entryClass);
mainMethod.Invoke(null, new string[][] { parameters });
}
static Assembly CompileCode(Dictionary<string, List<string>> directives)
{
Microsoft.CSharp.CSharpCodeProvider csProvider = new Microsoft.CSharp.CSharpCodeProvider();
CompilerParameters options = new CompilerParameters();
options.GenerateExecutable = false;
options.GenerateInMemory = true;
options.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
if (directives.ContainsKey("assembly"))
foreach (var assembly in directives["assembly"])
options.ReferencedAssemblies.Add(Environment.ExpandEnvironmentVariables(assembly));
var files = directives.ContainsKey("include") ? directives["include"].ToArray() : new string[0];
for (var i = 0; i < files.Length; i++)
files[i] = Environment.ExpandEnvironmentVariables(files[i]);
CompilerResults results = csProvider.CompileAssemblyFromFile(options, files);
if (results.Errors.HasErrors || results.Errors.HasWarnings)
foreach (CompilerError error in results.Errors)
Console.WriteLine("COMPILATION " + (error.IsWarning ? "WARNING" : "ERROR") + ": " + error.ToString() + ": " + error.FileName + ":" + error.Line + "@" + error.Column);
Assert(!results.Errors.HasErrors, "e1204141031", "Execution aborted, compilation generated errors!");
return results.CompiledAssembly;
}
static Type getMainType(Assembly script, string typeFullName)
{
foreach (Type exportedType in script.GetExportedTypes())
if (exportedType.FullName == typeFullName)
return exportedType;
return null;
}
}
}
Program.cscript
using System;
using System;
namespace MyNameSpace{
public class MyClassName{
public static void Main(string[]args){
Console.WriteLine(args[0]+" "+args[1]);
}
}
}