CS Script Overview - oleg-shilo/cs-script.net-framework GitHub Wiki
_This top-level Wiki documentation in most of the cases is fully sufficient for the development with CS-Script. It reflects the current state of CS-Script and all most recent API changes. Though in some cases (e.g. legacy topics) you may find useful to consult the online documentation on the CS-Script Home Page.
Further reading:
When you start exploring CS-Script you will probably quickly notice that it is quite different comparing to other scripting solutions. The immediate candidates for comparison are Mono and Roslyn. Both of these solutions are very similar. They concentrate mostly on hosting the script engine and executing small pieces of code. Their documentation offers plenty of samples of executing simple statements like '1+2' or 'Console.WriteLine("Hello")'. It all makes an impression that these script engines were designed for a single objective - providing a hosting solution for execution of user specified C# fragments (e.g. REPL or work flow engine). The usual consideration scope of these solutions is often no larger then a single C# statement. Thus they offer no solution for:
- Executing a complete C# module (C# file).
- Executing C# file as an external process (e.g. from command-prompt).
- Linking multiple inter-dependent C# files at runtime and executing them as a single unit.
- Convenient way of referencing dependency assemblies.
- Debugging scripts.
- A 14 years old (since 2002) problem of memory leaking with every single C# statement executed in the current AppDomain.
- ...
Both Roslyn and Mono are fully capable of being used to build a derived solutions addressing the challenges listed above but they don't deal with them directly.
CS-Script is different as its objective is to provide a platform for executing scripts of any level of complexity and dependency as well as extending the applications with the functionality as rich as .NET can facilitate. In a way CS-Script to C# syntax is what Python platform to Python syntax.
CS-Script does answer the all scripting challenges including REPL and IDE. But what even more important CS-Script provides one unified interface (API) that normalizes all three major C# compiling technologies CodeDom, Roslyn and Mono. Thus while letting developers to have a single scripting codebase CS-Script makes the choice of a concrete compiling technology (e.g. Mono vs Roslyn) a simple matter of the configuration. For the complete comparative overview of the compiling technologies see the dedicated Script Hosting page.
CS-Script is one of the most mature C# scripting frameworks available today. CS-Script first public release is dated back to 2004. At that time .NET ecosystem didn't provide any scripting solution. What is even more intriguing is the fact that at that time Microsoft consistently refused any call for such a solution. It insisted that there is no need for scripting as it has no place in .NET domain. Thus CS-Script was a pioneering effort to bring scripting experience to the developers when .NET vendor failed to do so. The main idea of CS-Script is to allow "plain vanilla" C# code execution from both command-prompt and form any CLR application hosting the script engine.
Things have changed since then. Today Microsoft is behind the ongoing Roslyn effort - their own compiler-as-service solution. Mono also has their compiler-as-service (Mono.CSharp) released around 2010. Though CS-Script remains one of the best choices of scripting platform due to the unorthodox conceptual approaches and unique features not found in other solutions.
What makes CS-Script almost unique is the comprehensive approach to scripting as a software development technique that has various applications (beyond just simple "eval"). CS-Script was hugely influenced by Python. In fact many CS-Scrip features was 'borrowed' from Python: referencing external scripts and assemblies, caching, converting scripts into self-sufficient executables. Thus having Python in mind CS-Script provided the answer for both standalone (script file) execution by the script engine executable and hosted script (file or in-memory text) execution by the script engine hosted by the user application.
For the hosted script execution CS-Script provides one unified interface, which allows switching between underlying compiling services (Mono, Roslyn and CodeDom) without the need to change the hosting code.
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Roslyn;
//EvaluatorEngine.Mono;
//EvaluatorEngine.CodeDom;
var sqr = CSScript.Evaluator
.CreateDelegate(@"int Sqr(int a)
{
return a * a;
}");
var r = sqr(3);
Additional documentation
The simplest way to execute the C# script is to run the script engine executable (css.exe) and pass the script file as a parameter. The script file is a file containing an ordinary ECMA-compliant C# code. CS-Script currently targets Microsoft implementation of CLR (.NET 2.0/3.0/3.5/4.0/4.5) with full support on Mono. CS-Script is implements script caching that ensures that the script file is never compiler unless it has change since the first execution or it is the first execution. This in turn allows a remarkable performance for the script execution, which is identical to the performance of the fully compiled assembly. Thus CS-Script implements JIT compilation but not within the scope of the code fragments (e.g. .NET JIT compilation) but within the scope of whole script file.
Some of the important features of CS-Script are:
- Including (referencing) dependency scripts from the main script
- Referencing external assemblies from the script
- Automatic referencing external assemblies based on analyses of the script imported namaspaces ('usings')
- Automatic resolving (downloading and referencing) NuGet packages
- Possibility to plug in external compiling services for supporting alternative script syntax (e.g. VB, C++)
- Scripts can be executed on Windows, Linux and OS X (last two will require Mono)
- Full integration with Windows, Visual Studio and Notepad++ (CS-Script extension for Notepad++ brings true Intellisense to the 'peoples editor')
- ...
You can find all the details about the stand alone script execution in the online documentation.
The default CS-Script distribution includes various components that make scripting a comfortable experience and yet it in may cases a single script engine file is sufficient for the scripting execution.
The most convenient way of installing CS-Script is to get it from Chocolaty (Windows equivalent of Linux apt-get)
NOTE: Due to the fact that C# 6.0 compiler (Roslyn) is a beta product it is not enabled by default. The full C# 6.0 support overview can be found here: .NET 4.6 Support.
Additional documentation
CS-Script can be hosted by any CLR application. The easiest way to do this is to add it as a NuGet package. CS-Script allows executing entire script files or C# code fragments. The very original implementation of hosted script execution was based on CodeDom API, which is available in all distributions of .NET and Mono. Thus it combines low dependency and ultimate portability.
Later CS-Script support alternative (compiler-as-service) compiling services has been added:
- End of 2012 CS-Script v3.5: Mono Evaluator (Mono.CSharp.dll v.4.0.0.0)
- End of 2015 CS-Script v3.10: Roslyn Compilers Beta release v1.2.0-beta-20151211-01
It is entirely up to developer to decide which compiling engine to use. The choice can be dictated by performance, deployment and maintainability considerations but not the convenience of the hosting API. This is because CS-Script encapsulates all three supported C# compilers into a single unified interface CSScript.Evaluator. Thus changing the compiling engine becomes a merely configuration exercise.
NOTE: By default CSScript.Evaluator
always returns a new instance of IEvaluator
. If this behavior is undesired change the evaluator access policy by setting CSScript.EvaluatorConfig.Access
value.
The evaluator allow executing either code fragments or entire class(es) definitions. Script can automatically access host types without any restrictions except types visibility (public vs. private). Scripted objects can be accessed dynamically (via 'dynamic') or statically via interface inheritance or duck-typing or via strongly typed delegates:
Accessing the script members dynamically:
dynamic script = CSScript.Evaluator
.LoadCode(@"using System;
public class Script
{
public int Sum(int a, int b)
{
return a+b;
}
}");
int result = script.Sum(1, 2);
Loading strongly typed delegate:
var product = CSScript.Evaluator
.LoadDelegate<Func<int, int, int>>(
@"int Product(int a, int b)
{
return a * b;
}");
int result = product(3, 2);
Interface alignment (duck-typing). Note that class Script doesn't inherit from ICalc. Instead the script engine wraps the script object into dynamically generated proxy of ICals type:
public interface ICalc
{
int Sum(int a, int b);
}
...
ICalc script = CSScript.Evaluator
.LoadCode<ICalc>(@"using System;
public class Script
{
public int Sum(int a, int b)
{
return a+b;
}
}");
int result = script.Sum(1, 2);
While Mono and Roslyn bring some benefits in many cases CodeDom driven execution remains the most practical solution. Particularly because it is the only solution that allows script debugging. You can find all the details about the hosted script execution on this page: Hosted Script Execution.