Click here to Skip to main content
15,894,907 members
Articles / Programming Languages / C#

C# Script: The Missing Puzzle Piece

Rate me:
Please Sign up or sign in to vote.
4.88/5 (184 votes)
6 Aug 2014MIT24 min read 1.3M   9.4K   531  
An article on a "scripting engine" for the C# language
using System;
using System.IO;
using System.Reflection;
using System.Diagnostics;
using CSScriptLibrary;

//css_reference common.dll;

class Script
{
	static void OnDataHandled(object info)
	{
		Console.WriteLine("\nClient has received notification: "+info.ToString());
	}

	static void Main(string[] args)
	{
		string scriptFile = ResolveFile(@"script.cs");
		DataHandler handler = ScriptLoader_ByLib_Fast_Debug.GetDataHandler(scriptFile);
	
		Data data = new Data("test", 777, 1, new NotifyParentDelegate(OnDataHandled));
		Console.WriteLine("\nData before processing:\n" + handler.Print(data));
		
		handler.Handle(ref data);
		
		Console.WriteLine("\nData after processing:\n" + handler.Print(data));
		Console.WriteLine("\nData was processed by "+handler.Who());
	}

	static string ResolveFile(string fileName)
	{
		return Path.IsPathRooted(fileName) ? fileName : Path.Combine(Environment.CurrentDirectory, fileName);
	}
}

class ScriptLoader_ByLib_Fast
{
	public static DataHandler GetDataHandler(string fileName)
	{
		//I am assuming fileName has static 'DataHandler Script.CreateDataHandler(void)'
		//otherwise System.NullReferenceException will be thrown
		Module module = CSScript.Load(fileName, null, false).GetModules()[0];
		Type type = module.FindTypes(Module.FilterTypeName, "Script")[0];
		MethodInfo method = type.GetMethod("CreateDataHandler"); 
		return (DataHandler)method.Invoke(null, null);
	}
}

class ScriptLoader_ByLib_Fast_Debug
{
	public static DataHandler GetDataHandler(string fileName)
	{
		//the best result I have got with VS debugger
		Module module = CSScript.Load(fileName, null, true).GetModules()[0];
		Type type = module.FindTypes(Module.FilterTypeName, "Script")[0];
		MethodInfo method = type.GetMethod("CreateDataHandler"); 
		return (DataHandler)method.Invoke(null, null);
	}
}

class ScriptLoader_ByLib_Browse
{
	public static DataHandler GetDataHandler(string fileName)
	{
		foreach (Module m in CSScript.Load(fileName, null, false).GetModules())
		{
			foreach (Type t in m.GetTypes())
			{
				foreach (MemberInfo mi in t.GetMembers(BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static))
				{
					if (mi.Name == "CreateDataHandler")
						return (DataHandler)t.GetMethod(mi.Name).Invoke(null, null);
				}
			}
		}
		throw new Exception("Cannot find method 'CreateDataHandler'");
	}
}
class ScriptLoader_ByLib_Browse_Clean
{
	public static DataHandler GetDataHandler(string fileName)
	{
		string asmFileName = CSScript.Compile(fileName, null, false);
		AssemblyName asmName = AssemblyName.GetAssemblyName(asmFileName);
		Assembly asm = AppDomain.CurrentDomain.Load(asmName);

		foreach (Module m in asm.GetModules())
		{
			foreach (Type t in m.GetTypes())
			{
				foreach (MemberInfo mi in t.GetMembers(BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static))
				{
					if (mi.Name == "CreateDataHandler")
						return (DataHandler)t.GetMethod(mi.Name).Invoke(null, null);
				}
			}
		}

		throw new Exception("Cannot find method 'CreateDataHandler'");
	}
}
class ScriptLoader_ByExe
{
	public static DataHandler GetDataHandler(string fileName)
	{
		Assembly asm = LoadScript(fileName);
		return (DataHandler)GetMethod(asm, "CreateDataHandler", bFlags).Invoke(null, null);
	}
	private static Assembly LoadScript(string scriptName)
	{
		if (!File.Exists(scriptName))
			throw new IOException("Cannot find " + scriptName);

		Process myProcess = new Process();
		myProcess.StartInfo.FileName = "cscscript.exe";
		myProcess.StartInfo.Arguments = "/nl /ca " + scriptName;
		myProcess.StartInfo.UseShellExecute = false;
		myProcess.StartInfo.CreateNoWindow = true;
		myProcess.Start();
		myProcess.WaitForExit();

		string assemblyFile = Path.ChangeExtension(scriptName, ".csc");
		if (!File.Exists(assemblyFile))
			throw new Exception("Cannot compile " + scriptName);

		AssemblyName asmName = AssemblyName.GetAssemblyName(assemblyFile);
		return AppDomain.CurrentDomain.Load(asmName);
	}
	private static MethodInfo GetMethod(Assembly assembly, string name, BindingFlags bf)
	{
		foreach (Module m in assembly.GetModules())
		{
			foreach (Type t in m.GetTypes())
			{
				foreach (MemberInfo mi in t.GetMembers(bf))
				{
					if (mi.Name == name)
						return t.GetMethod(mi.Name);
				}
			}
		}
		throw new Exception("Cannot find method " + name);
	}
	private const BindingFlags bFlags = BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Program Manager
Australia Australia
I was born in Ukraine. After completing the university degree worked there as a Research Chemist. Last 23 years I live in Australia where I've got my second qualification as a Software Engineer.

"I am the lucky one: I do enjoy what I am doing!"

Comments and Discussions