{{error}}
{{(quickSearchResults.length>10)?'10+':(quickSearchResults.length)}} {{(quickSearchResults.length==1)?'result':'results'}}
{{result.title}} {{result.timeStamp | mysql2ymd }}
I am sorry, no such article was written yet.
Scripted C# - or how to run dynamic C# code, without compilation
Scripted C# - or how to run dynamic C# code, without compilation
As I started to develop small applications in C#, I thought why shouldn't I use the same paradigms that I used in Java... dynamic code execution, execution without compile/build/deploy process, hot-swap, etc.

I am far away from acomplishing the same functionality, but I started with writing a small program (81 lines) mentioned below.

When executing, it is able to compile and execute C# code that is written in text files, on the spot.

The mechanism is quite simple: it expects in the command line the name of an XML file (mentioned below this script) that describes:
  • the list of CS files that should be compiled;
  • the list of external binaries, if required;
  • the title of the application;
  • the entry point (the class name that contains the Main function).
An example (SMTPServer.csscriptof the input XML looks like attached.
Useful information:
  • the class mentioned in the CSScript/EntryClass node must have a Main(string[]args) method;
  • the Main method must be public and static!
  • additional parameters to be sent to the Main method are added to the executed command line!
Example of using the script attached.
In my development (that I started yesterday evening) I used some information from the following links:
The application code is straight forward, and I don't think any comment is required. If you need any comment, then either you should learn programming, or study a bit some C-like languages.

If you wonder why I don't also give the EXE file, please feel free to open the Visual Studio, create an empty project, add a class and paste this code.
RunCS.cs
using System;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Xml;
using System.Xml.XPath;
namespace CSScript {
    static class CSScript {
        static void Fatal(string message) {
            Console.WriteLine("FATAL: "+message);
            Console.ReadKey();
            Environment.Exit(1);
        }
        static private XPathNavigator config;
        [STAThread]
        static void Main(string[] args) {
            try {
                if(args.Length<1)
                    Fatal("Usage: CSScript <csscript_file> [<params>]");
                if(!System.IO.File.Exists(args[0]))
                    Fatal("e1204141741 - File '"+args[0]+"' does not exist");
                XmlDocument configXml=new XmlDocument();
                configXml.Load(args[0]);
                config=configXml.CreateNavigator();
                if(config.Select("CSScript/EntryClass").Count!=1)
                    Fatal("'EntryClass' must be one and only one");
                if(config.Select("CSScript/Title").Count!=1)
                    Fatal("'Title' must be one and only one");
                Assembly compiledScript=CompileCode();
                var title=config.SelectSingleNode("CSScript/Title");
                Console.WriteLine("Starting application '{0}'",title);
                Console.Title=title.ToString();
                string[] parameters=new string[args.Length-1];
                for(var i=1;i<args.Length;i++)
                    parameters[i-1]=args[i];
                if(compiledScript==null)
                    Fatal("e1204141028 - Application not compiled properly.");
                var entryClass=config.SelectSingleNode("CSScript/EntryClass").ToString();
                Type mainType=getMainType(compiledScript,entryClass);
                if(mainType==null)
                    Fatal("e1204141029 - Type "+entryClass+" could not be found");
                var mainMethod=mainType.GetMethod("Main");
                if(mainMethod==null)
                    Fatal("e1204141030 - Main Method 'Main' not found in class "+entryClass);
                mainMethod.Invoke(null,new string[][] { parameters });
                Console.Write("Press any key to exit...");
                Console.ReadKey();
            } catch(Exception e) {
                Fatal("e1204141747 - "+e.ToString());
            }
        }

        static Assembly CompileCode() {
            Microsoft.CSharp.CSharpCodeProvider csProvider=new Microsoft.CSharp.CSharpCodeProvider();
            CompilerParameters options=new CompilerParameters();
            options.GenerateExecutable=false;
            options.GenerateInMemory=true;
            options.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
            foreach(var assembly in config.Select("CSScript/ReferencedAssemblies/File"))
                options.ReferencedAssemblies.Add(assembly.ToString());
            var sources=config.Select("CSScript/CSSources/File");
            string[]files=new string[sources.Count];
            for(int i=0;i<files.Length;i++) {
                sources.MoveNext();
                files[i]=sources.Current.ToString();
            }
            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);
            if(results.Errors.HasErrors)
                Fatal("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;
        }
    }
}
SMTPServer.csscript
<CSScript>
	<!-- this title should appear in the window's titlebar -->
	<Title>SMTPServer</Title>
	<!-- list of referenced assemblies - path might require updates for various computers -->
	<ReferencedAssemblies>
		<File>c:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.dll</File>
		<File>c:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.XML.dll</File>
	</ReferencedAssemblies>
	
	<!-- Entry class in syntax <namespace>.<class name> -->
	<!-- This class is expected to contain a Main method -->
	<EntryClass>SMTPServer.SMTPServer</EntryClass>

	<!-- The list of CS source files, relative to the application -->
	<CSSources>
		<File>csSources\Listener.cs</File>
		<File>csSources\MXDiscovery.cs</File>
		<File>csSources\Sender.cs</File>
		<File>csSources\SMTP.cs</File>
		<File>csSources\SMTPServer.cs</File>
	</CSSources>
</CSScript>
start.cmd
WARNING: Language not known: `cmd`
CSScript.exe SMTPServer.csscript listener-ip=0.0.0.0 listener-port=25