Quantcast
Channel: CS-Script Source
Viewing all 355 articles
Browse latest View live

Updated Wiki: Hosted Script Execution

$
0
0

THIS DOCUMENT IS UNDER DEVELOPMENT


Because of the large scale of the CS-Script online documentation it can be challenging to find a specific information within it. Thus the all major details about hosting the script engine in applications are described on the single page: Script Hosting Guideline.

Hosted script execution

CS-Script can be hosted by any CLR application. The best way to bring scripting in your application is to add the corresponding NuGet package to your Visual Studio project :

Install-Package CS-Script.bin
or
Install-Package CS-Script 

'CS-Script.bin' package contains only binaries (e.g. CSScriptLibrary.dll) and 'CS-Script' contains binaries and sample files. The code samples in this article are consistent with the samples distributed with the NuGet package.

CSScriptLibrary.dll is the actual assembly implementing CS-Script as a class library. It is targeting .NET v4.0/4.5. However the package from the CodePlex Releases page always contains CSScriptLibrary.dll builds for earlier versions of .NET (<cs-script>\lib\Bin).
Setting up Evaluator
Any application hosting CS-Script engine can execute C# code containing either fully defined types or code fragments (e.g. methods). It is important to note that CS-Script is neither a compiler nor evaluator. It is rather a runtime environment that relies for the code compilation by the standard compiling toolset available with any .NET or Mono installation. The first compiling services CS-Script integrated was CodeDom. It is the very original compiler-as-service that was available starting from the first release of .NET.

While many may not consider CodeDom as 'true compiler-as-service', in reality, it actually is. The problem with CodeDom API is that it's inconvenient in require a great deal of manual runtime configuration. And it is exactly what CS-Script is addressing. Later on some alternative proprietary compiler-as-service solutions became available. First Mono Evaluator and later Roslyn (currently still Beta). Both demonstrated a completely different approach towards what good scripting API should look like. Thus all three compiling platforms are mutually inconsistent and only partially overlapping in with respect to functionality.

And this is where CS-Script comes to the rescue. It provides one unified generic interface transparent to the underlying compiler technology. You can have your script code executed by ether of three supported compilers without affecting your hosting code.

The code below demonstrates creating (compiling) a delegate.

var sqr = CSScript.Evaluator
                  .CreateDelegate(@"int Sqr(int a)
                                    {
                                        return a * a;
                                    }");
var r = sqr(3); 

By default CSScript.Evaluator references Mono compiler. However you can change this behavior globally by re-configuring the default compiler:

CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Mono;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Roslyn;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;

Alternatively you can access the corresponding compiler via a dedicated member property:

CSScript.MonoEvaluator.CreateDelegate(...
CSScript.RoslynEvaluator.CreateDelegate(...
CSScript.CodeDomEvaluator.CreateDelegate(...

Every time a CSScript.*Evaluator property is accessed a new instance of the corresponding evaluator is created and returned to the caller. Though this can be changed by re-configuring the evaluator access type to return the reference to the global evaluator object:

CSScript.EvaluatorConfig.Access = EvaluatorAccess.Singleton;


Executing the scripts
The evaluator allows executing code containing definition a type (or multiple types):

Assembly script = CSScript.Evaluator
                          .CompileCode(@"using System;
                                         public class Script
                                         {
                                             public int Sum(int a, int b)
                                             {
                                                 return a+b;
                                             }
                                         }");
         

Alternativelly you can compile code containing only method(s). In this case Evaluator will wrap the method code into a class definition with name DynamicClass:

Assembly script = CSScript.Evaluator
                          .CompileMethod(@"int Sum(int a, int b)
                                           {
                                               return a+b;
                                           }");
         

Further access to the script members can be simplified by using Evaluator.Load*, which compiles the code and returns the instance of the first class in compiled assembly:

dynamic script = CSScript.MonoEvaluator
                         .LoadMethod(@"int Product(int a, int b)
                                       {
                                           return a * b;
                                       }");

int result = script.Product(3, 2);

Note that in the code below the method Product is invoked with 'dynamic' keyword, meaning that the host application cannot do any compile-time checking in the host code. In many cases it is oOK, though sometimes it is desirable that the script object was strongly typed. The easiest way to achieve this is to use interfaces:

publicinterface ICalc
{
    int Sum(int a, int b);
}
...
ICalc script = (ICalc)CSScript.Evaluator
                              .LoadCode(@"using System;
                                          public class Script : ICalc
                                          {
                                              public int Sum(int a, int b)
                                              {
                                                  return a+b;
                                              }
                                          }");
int result = script.Sum(1, 2);

Not that you can also use an Interface alignment (duck-typing) technique, which allows 'aligning' the script object to the interface even if it is not implementing this interface. It is achieved by evaluator wrapping the script object into dynamically generated proxy of the interface (e.g. ICals) type:

ICalc script = CSScript.Evaluator
                       .LoadCode<ICalc>(@"using System;
                                          public class Script
                                          {
                                              public int Sum(int a, int b)
                                              {
                                                  return a+b;
                                              }
                                          }");
      

Evaluator also allows compiling method scripts into class-less delegates:

var sqr = CSScript.Evaluator
                  .CreateDelegate<int>(@"int Sqr(int a)
                                         {
                                             return a * a;
                                         }");
int result = sqr(3); 

In the code above CreateDelegate returns MethodDelegate<T>, which is semi-dynamic by nature. It is strongly typed by return type and dynamically typed (thanks to 'params') by method parameters:
publicdelegate T MethodDelegate<T>(paramsobject[] paramters);

Though if strongly typed delegate is preferred then you can use LoadDelegate instead:

Func<int, int, int> product = CSScript.Evaluator
                                      .LoadDelegate<Func<int, int, int>>(
                                              @"int Product(int a, int b)
                                                {
                                                    return a * b;
                                                }");
int result = product(3, 2);

Updated Wiki: Hosted Script Execution

$
0
0

THIS DOCUMENT IS UNDER DEVELOPMENT


Because of the large scale of the CS-Script online documentation it can be challenging to find a specific information within it. Thus the all major details about hosting the script engine in applications are described on the single page: Script Hosting Guideline.

Hosted script execution

CS-Script can be hosted by any CLR application. The best way to bring scripting in your application is to add the corresponding NuGet package to your Visual Studio project :

Install-Package CS-Script.bin
or
Install-Package CS-Script 

'CS-Script.bin' package contains only binaries (e.g. CSScriptLibrary.dll) and 'CS-Script' contains binaries and sample files. The code samples in this article are consistent with the samples distributed with the NuGet package.

CSScriptLibrary.dll is the actual assembly implementing CS-Script as a class library. It is targeting .NET v4.0/4.5. However the package from the CodePlex Releases page always contains CSScriptLibrary.dll builds for earlier versions of .NET (<cs-script>\lib\Bin).
Setting up Evaluator
Any application hosting CS-Script engine can execute C# code containing either fully defined types or code fragments (e.g. methods). It is important to note that CS-Script is neither a compiler nor evaluator. It is rather a runtime environment that relies for the code compilation by the standard compiling toolset available with any .NET or Mono installation. The first compiling services CS-Script integrated was CodeDom. It is the very original compiler-as-service that was available starting from the first release of .NET.

While many may not consider CodeDom as 'true compiler-as-service', in reality, it actually is. The problem with CodeDom API is that it's inconvenient in require a great deal of manual runtime configuration. And it is exactly what CS-Script is addressing. Later on some alternative proprietary compiler-as-service solutions became available. First Mono Evaluator and later Roslyn (currently still Beta). Both demonstrated a completely different approach towards what good scripting API should look like. Thus all three compiling platforms are mutually inconsistent and only partially overlapping in with respect to functionality.

And this is where CS-Script comes to the rescue. It provides one unified generic interface transparent to the underlying compiler technology. You can have your script code executed by ether of three supported compilers without affecting your hosting code.

The code below demonstrates creating (compiling) a delegate.

var sqr = CSScript.Evaluator
                  .CreateDelegate(@"int Sqr(int a)
                                    {
                                        return a * a;
                                    }");
var r = sqr(3); 

By default CSScript.Evaluator references Mono compiler. However you can change this behavior globally by re-configuring the default compiler:

CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Mono;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Roslyn;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;

Alternatively you can access the corresponding compiler via a dedicated member property:

CSScript.MonoEvaluator.CreateDelegate(...
CSScript.RoslynEvaluator.CreateDelegate(...
CSScript.CodeDomEvaluator.CreateDelegate(...

Every time a CSScript.*Evaluator property is accessed a new instance of the corresponding evaluator is created and returned to the caller. Though this can be changed by re-configuring the evaluator access type to return the reference to the global evaluator object:

CSScript.EvaluatorConfig.Access = EvaluatorAccess.Singleton;


Executing the scripts
The evaluator allows executing code containing definition a type (or multiple types):

Assembly script = CSScript.Evaluator
                          .CompileCode(@"using System;
                                         public class Script
                                         {
                                             public int Sum(int a, int b)
                                             {
                                                 return a+b;
                                             }
                                         }");
         

Alternativelly you can compile code containing only method(s). In this case Evaluator will wrap the method code into a class definition with name DynamicClass:

Assembly script = CSScript.Evaluator
                          .CompileMethod(@"int Sum(int a, int b)
                                           {
                                               return a+b;
                                           }");
         

Further access to the script members can be simplified by using Evaluator.Load*, which compiles the code and returns the instance of the first class in compiled assembly:

dynamic script = CSScript.Evaluator
                         .LoadMethod(@"int Product(int a, int b)
                                       {
                                           return a * b;
                                       }");

int result = script.Product(3, 2);

Note that in the code below the method Product is invoked with 'dynamic' keyword, meaning that the host application cannot do any compile-time checking in the host code. In many cases it is oOK, though sometimes it is desirable that the script object was strongly typed. The easiest way to achieve this is to use interfaces:

publicinterface ICalc
{
    int Sum(int a, int b);
}
...
ICalc script = (ICalc)CSScript.Evaluator
                              .LoadCode(@"using System;
                                          public class Script : ICalc
                                          {
                                              public int Sum(int a, int b)
                                              {
                                                  return a+b;
                                              }
                                          }");
int result = script.Sum(1, 2);

Not that you can also use an Interface alignment (duck-typing) technique, which allows 'aligning' the script object to the interface even if it is not implementing this interface. It is achieved by evaluator wrapping the script object into dynamically generated proxy of the interface (e.g. ICals) type:

ICalc script = CSScript.Evaluator
                       .LoadCode<ICalc>(@"using System;
                                          public class Script
                                          {
                                              public int Sum(int a, int b)
                                              {
                                                  return a+b;
                                              }
                                          }");
      

Evaluator also allows compiling method scripts into class-less delegates:

var sqr = CSScript.Evaluator
                  .CreateDelegate<int>(@"int Sqr(int a)
                                         {
                                             return a * a;
                                         }");
int result = sqr(3); 

In the code above CreateDelegate returns MethodDelegate<T>, which is semi-dynamic by nature. It is strongly typed by return type and dynamically typed (thanks to 'params') by method parameters:

publicdelegate T MethodDelegate<T>(paramsobject[] paramters);

Though if strongly typed delegate is preferred then you can use LoadDelegate instead:

Func<int, int, int> product = CSScript.Evaluator
                                      .LoadDelegate<Func<int, int, int>>(
                                              @"int Product(int a, int b)
                                                {
                                                    return a * b;
                                                }");
int result = product(3, 2);

Script can automatically access all types of the host application without any restrictions according the types visibility (public vs. private). This is the evaluator by default references (for the script) all loaded assemblies of the current AppDomain. However custom assembly referencing is also available:

IEvaluator evaluator = CSScript.Evaluator;
string code = "<some C# code>";

evaluator.Reset(false); //clear all ref assemblies

evaluator.ReferenceAssembly(Assembly.GetExecutingAssembly())
         .ReferenceAssembly(@"c:\some_dir\myAsm.dll")                         
         .ReferenceAssemblyByName("System.Xml")                         
         .ReferenceAssemblyByNamespace("System.Windows.Forms")
         .ReferenceAssemblyOf(this)                         
         .ReferenceAssemblyOf<string>()                         
         .ReferenceAssembliesFromCode(code)
         .ReferenceDomainAssemblies();  
         
dynamic script = evaluator.LoadCode(code);

The code above is a pseudo code that is not particularly useful but it does demonstrates the referencing technique very well.
Method ReferenceAssembliesFromCode is particularly interesting as it utilises CS-Script ability to analyse script code and find out what assemblies the script needs to reference. Read this article for more details.

Updated Wiki: Hosted Script Execution

$
0
0

THIS DOCUMENT IS UNDER DEVELOPMENT


Because of the large scale of the CS-Script online documentation it can be challenging to find a specific information within it. Thus the all major details about hosting the script engine in applications are described on the single page: Script Hosting Guideline.
Next - Choosing Compiler Engine

Hosted script execution

CS-Script can be hosted by any CLR application. The best way to bring scripting in your application is to add the corresponding NuGet package to your Visual Studio project :

Install-Package CS-Script.bin
or
Install-Package CS-Script 

'CS-Script.bin' package contains only binaries (e.g. CSScriptLibrary.dll) and 'CS-Script' contains binaries and sample files. The code samples in this article are consistent with the samples distributed with the NuGet package.

CSScriptLibrary.dll is the actual assembly implementing CS-Script as a class library. It is targeting .NET v4.0/4.5. However the package from the CodePlex Releases page always contains CSScriptLibrary.dll builds for earlier versions of .NET (<cs-script>\lib\Bin).
Setting up Evaluator
Any application hosting CS-Script engine can execute C# code containing either fully defined types or code fragments (e.g. methods). It is important to note that CS-Script is neither a compiler nor evaluator. It is rather a runtime environment that relies for the code compilation by the standard compiling toolset available with any .NET or Mono installation. The first compiling services CS-Script integrated was CodeDom. It is the very original compiler-as-service that was available starting from the first release of .NET.

While many may not consider CodeDom as 'true compiler-as-service', in reality, it actually is. The problem with CodeDom API is that it's inconvenient in require a great deal of manual runtime configuration. And it is exactly what CS-Script is addressing. Later on some alternative proprietary compiler-as-service solutions became available. First Mono Evaluator and later Roslyn (currently still Beta). Both demonstrated a completely different approach towards what good scripting API should look like. Thus all three compiling platforms are mutually inconsistent and only partially overlapping in with respect to functionality.

And this is where CS-Script comes to the rescue. It provides one unified generic interface transparent to the underlying compiler technology. You can have your script code executed by ether of three supported compilers without affecting your hosting code.

The code below demonstrates creating (compiling) a delegate.

var sqr = CSScript.Evaluator
                  .CreateDelegate(@"int Sqr(int a)
                                    {
                                        return a * a;
                                    }");
var r = sqr(3); 

By default CSScript.Evaluator references Mono compiler. However you can change this behavior globally by re-configuring the default compiler:

CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Mono;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Roslyn;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;

Alternatively you can access the corresponding compiler via a dedicated member property:

CSScript.MonoEvaluator.CreateDelegate(...
CSScript.RoslynEvaluator.CreateDelegate(...
CSScript.CodeDomEvaluator.CreateDelegate(...

Every time a CSScript.*Evaluator property is accessed a new instance of the corresponding evaluator is created and returned to the caller. Though this can be changed by re-configuring the evaluator access type to return the reference to the global evaluator object:

CSScript.EvaluatorConfig.Access = EvaluatorAccess.Singleton;


Executing the scripts
The evaluator allows executing code containing definition a type (or multiple types):

Assembly script = CSScript.Evaluator
                          .CompileCode(@"using System;
                                         public class Script
                                         {
                                             public int Sum(int a, int b)
                                             {
                                                 return a+b;
                                             }
                                         }");
         

Alternativelly you can compile code containing only method(s). In this case Evaluator will wrap the method code into a class definition with name DynamicClass:

Assembly script = CSScript.Evaluator
                          .CompileMethod(@"int Sum(int a, int b)
                                           {
                                               return a+b;
                                           }");
         

Further access to the script members can be simplified by using Evaluator.Load*, which compiles the code and returns the instance of the first class in compiled assembly:

dynamic script = CSScript.Evaluator
                         .LoadMethod(@"int Product(int a, int b)
                                       {
                                           return a * b;
                                       }");

int result = script.Product(3, 2);

Note that in the code below the method Product is invoked with 'dynamic' keyword, meaning that the host application cannot do any compile-time checking in the host code. In many cases it is oOK, though sometimes it is desirable that the script object was strongly typed. The easiest way to achieve this is to use interfaces:

publicinterface ICalc
{
    int Sum(int a, int b);
}
...
ICalc script = (ICalc)CSScript.Evaluator
                              .LoadCode(@"using System;
                                          public class Script : ICalc
                                          {
                                              public int Sum(int a, int b)
                                              {
                                                  return a+b;
                                              }
                                          }");
int result = script.Sum(1, 2);

Not that you can also use an Interface alignment (duck-typing) technique, which allows 'aligning' the script object to the interface even if it is not implementing this interface. It is achieved by evaluator wrapping the script object into dynamically generated proxy of the interface (e.g. ICals) type:

ICalc script = CSScript.Evaluator
                       .LoadCode<ICalc>(@"using System;
                                          public class Script
                                          {
                                              public int Sum(int a, int b)
                                              {
                                                  return a+b;
                                              }
                                          }");
      

Evaluator also allows compiling method scripts into class-less delegates:

var sqr = CSScript.Evaluator
                  .CreateDelegate<int>(@"int Sqr(int a)
                                         {
                                             return a * a;
                                         }");
int result = sqr(3); 

In the code above CreateDelegate returns MethodDelegate<T>, which is semi-dynamic by nature. It is strongly typed by return type and dynamically typed (thanks to 'params') by method parameters:

publicdelegate T MethodDelegate<T>(paramsobject[] paramters);

Though if strongly typed delegate is preferred then you can use LoadDelegate instead:

Func<int, int, int> product = CSScript.Evaluator
                                      .LoadDelegate<Func<int, int, int>>(
                                              @"int Product(int a, int b)
                                                {
                                                    return a * b;
                                                }");
int result = product(3, 2);

Script can automatically access all types of the host application without any restrictions according the types visibility (public vs. private). This is the evaluator by default references (for the script) all loaded assemblies of the current AppDomain. However custom assembly referencing is also available:

IEvaluator evaluator = CSScript.Evaluator;
string code = "<some C# code>";

evaluator.Reset(false); //clear all ref assemblies

evaluator.ReferenceAssembly(Assembly.GetExecutingAssembly())
         .ReferenceAssembly(@"c:\some_dir\myAsm.dll")                         
         .ReferenceAssemblyByName("System.Xml")                         
         .ReferenceAssemblyByNamespace("System.Windows.Forms")
         .ReferenceAssemblyOf(this)                         
         .ReferenceAssemblyOf<string>()                         
         .ReferenceAssembliesFromCode(code)
         .ReferenceDomainAssemblies();  
         
dynamic script = evaluator.LoadCode(code);

The code above is a pseudo code that is not particularly useful but it does demonstrates the referencing technique very well.
Method ReferenceAssembliesFromCode is particularly interesting as it utilizes CS-Script ability to analyse script code and find out what assemblies the script needs to reference. Read this article for more details.

Maintainability
While all three supported compiling services normalized via Evaluator interface some of the critical features only available via dedicated Evaluators. Thus CodeDom Evaluator is a 'champion' of all compilers as no others can match its flexibility. Thus it is the only compiler platform that supports script debugging:

CSScript.EvaluatorConfig.DebugBuild = true;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;

dynamic script = CSScript.Evaluator
                            .LoadCode(@"using System;
                                        using System.Diagnostics;
                                        public class Script
                                        {
                                            public int Sum(int a, int b)
                                            {
                                                Debug.Assert(false, ""Testing CS-Script debugging..."");
                                                return a+b;
                                            }
                                        }");

var r = script.Sum(3, 4); //triggers the assertion

Another very important CodeDom feature that is not available with other compilers is the ability to unload already loaded scripts. Though it is outside of this article scope and you can read more about unique CodeDom features in Choosing Compiler Engine article.
Conclusion
This article briefly described the hosting API but you will find more samples in the downloadable package (on Releases page) in <cs-script>\samples\Hosting directory.
The hosting API itself is made compiler transparent so in terms of development effort it doesn't matter which compiler you use. However it doesn't mean that all compilers are offering the same functionality. The next article Choosing Compiler Engine will help you to chose the compiler most suitable for your task.

Updated Wiki: Hosted Script Execution

$
0
0
Related articles:

Hosted script execution

CS-Script can be hosted by any CLR application. The best way to bring scripting in your application is to add the corresponding NuGet package to your Visual Studio project :

Install-Package CS-Script.bin
or
Install-Package CS-Script 

'CS-Script.bin' package contains only binaries (e.g. CSScriptLibrary.dll) and 'CS-Script' contains binaries and sample files. The code samples in this article are consistent with the samples distributed with the NuGet package.

CSScriptLibrary.dll is the actual assembly implementing CS-Script as a class library. It is targeting .NET v4.0/4.5. However the package from the CodePlex Releases page always contains CSScriptLibrary.dll builds for earlier versions of .NET (<cs-script>\lib\Bin).
Setting up Evaluator
Any application hosting CS-Script engine can execute C# code containing either fully defined types or code fragments (e.g. methods). It is important to note that CS-Script is neither a compiler nor evaluator. It is rather a runtime environment that relies for the code compilation by the standard compiling toolset available with any .NET or Mono installation. The first compiling services CS-Script integrated was CodeDom. It is the very original compiler-as-service that was available starting from the first release of .NET.

While many may not consider CodeDom as 'true compiler-as-service', in reality, it actually is. The problem with CodeDom API is that it's inconvenient in require a great deal of manual runtime configuration. And it is exactly what CS-Script is addressing. Later on some alternative proprietary compiler-as-service solutions became available. First Mono Evaluator and later Roslyn (currently still Beta). Both demonstrated a completely different approach towards what good scripting API should look like. Thus all three compiling platforms are mutually inconsistent and only partially overlapping in with respect to functionality.

And this is where CS-Script comes to the rescue. It provides one unified generic interface transparent to the underlying compiler technology. You can have your script code executed by ether of three supported compilers without affecting your hosting code.

The code below demonstrates creating (compiling) a delegate.

var sqr = CSScript.Evaluator
                  .CreateDelegate(@"int Sqr(int a)
                                    {
                                        return a * a;
                                    }");
var r = sqr(3); 

By default CSScript.Evaluator references Mono compiler. However you can change this behavior globally by re-configuring the default compiler:

CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Mono;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Roslyn;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;

Alternatively you can access the corresponding compiler via a dedicated member property:

CSScript.MonoEvaluator.CreateDelegate(...
CSScript.RoslynEvaluator.CreateDelegate(...
CSScript.CodeDomEvaluator.CreateDelegate(...

Every time a CSScript.*Evaluator property is accessed a new instance of the corresponding evaluator is created and returned to the caller. Though this can be changed by re-configuring the evaluator access type to return the reference to the global evaluator object:

CSScript.EvaluatorConfig.Access = EvaluatorAccess.Singleton;


Executing the scripts
The evaluator allows executing code containing definition a type (or multiple types):

Assembly script = CSScript.Evaluator
                          .CompileCode(@"using System;
                                         public class Script
                                         {
                                             public int Sum(int a, int b)
                                             {
                                                 return a+b;
                                             }
                                         }");
         

Alternativelly you can compile code containing only method(s). In this case Evaluator will wrap the method code into a class definition with name DynamicClass:

Assembly script = CSScript.Evaluator
                          .CompileMethod(@"int Sum(int a, int b)
                                           {
                                               return a+b;
                                           }");
         

Further access to the script members can be simplified by using Evaluator.Load*, which compiles the code and returns the instance of the first class in compiled assembly:

dynamic script = CSScript.Evaluator
                         .LoadMethod(@"int Product(int a, int b)
                                       {
                                           return a * b;
                                       }");

int result = script.Product(3, 2);

Note that in the code below the method Product is invoked with 'dynamic' keyword, meaning that the host application cannot do any compile-time checking in the host code. In many cases it is oOK, though sometimes it is desirable that the script object was strongly typed. The easiest way to achieve this is to use interfaces:

publicinterface ICalc
{
    int Sum(int a, int b);
}
...
ICalc script = (ICalc)CSScript.Evaluator
                              .LoadCode(@"using System;
                                          public class Script : ICalc
                                          {
                                              public int Sum(int a, int b)
                                              {
                                                  return a+b;
                                              }
                                          }");
int result = script.Sum(1, 2);

Not that you can also use an Interface alignment (duck-typing) technique, which allows 'aligning' the script object to the interface even if it is not implementing this interface. It is achieved by evaluator wrapping the script object into dynamically generated proxy of the interface (e.g. ICals) type:

ICalc script = CSScript.Evaluator
                       .LoadCode<ICalc>(@"using System;
                                          public class Script
                                          {
                                              public int Sum(int a, int b)
                                              {
                                                  return a+b;
                                              }
                                          }");
      

Evaluator also allows compiling method scripts into class-less delegates:

var sqr = CSScript.Evaluator
                  .CreateDelegate<int>(@"int Sqr(int a)
                                         {
                                             return a * a;
                                         }");
int result = sqr(3); 

In the code above CreateDelegate returns MethodDelegate<T>, which is semi-dynamic by nature. It is strongly typed by return type and dynamically typed (thanks to 'params') by method parameters:

publicdelegate T MethodDelegate<T>(paramsobject[] paramters);

Though if strongly typed delegate is preferred then you can use LoadDelegate instead:

Func<int, int, int> product = CSScript.Evaluator
                                      .LoadDelegate<Func<int, int, int>>(
                                              @"int Product(int a, int b)
                                                {
                                                    return a * b;
                                                }");
int result = product(3, 2);

Script can automatically access all types of the host application without any restrictions according the types visibility (public vs. private). This is the evaluator by default references (for the script) all loaded assemblies of the current AppDomain. However custom assembly referencing is also available:

IEvaluator evaluator = CSScript.Evaluator;
string code = "<some C# code>";

evaluator.Reset(false); //clear all ref assemblies

evaluator.ReferenceAssembly(Assembly.GetExecutingAssembly())
         .ReferenceAssembly(@"c:\some_dir\myAsm.dll")                         
         .ReferenceAssemblyByName("System.Xml")                         
         .ReferenceAssemblyByNamespace("System.Windows.Forms")
         .ReferenceAssemblyOf(this)                         
         .ReferenceAssemblyOf<string>()                         
         .ReferenceAssembliesFromCode(code)
         .ReferenceDomainAssemblies();  
         
dynamic script = evaluator.LoadCode(code);

The code above is a pseudo code that is not particularly useful but it does demonstrates the referencing technique very well.
Method ReferenceAssembliesFromCode is particularly interesting as it utilizes CS-Script ability to analyse script code and find out what assemblies the script needs to reference. Read this article for more details.

Maintainability
While all three supported compiling services normalized via Evaluator interface some of the critical features only available via dedicated Evaluators. Thus CodeDom Evaluator is a 'champion' of all compilers as no others can match its flexibility. Thus it is the only compiler platform that supports script debugging:

CSScript.EvaluatorConfig.DebugBuild = true;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;

dynamic script = CSScript.Evaluator
                            .LoadCode(@"using System;
                                        using System.Diagnostics;
                                        public class Script
                                        {
                                            public int Sum(int a, int b)
                                            {
                                                Debug.Assert(false, ""Testing CS-Script debugging..."");
                                                return a+b;
                                            }
                                        }");

var r = script.Sum(3, 4); //triggers the assertion

Another very important CodeDom feature that is not available with other compilers is the ability to unload already loaded scripts. Though it is outside of this article scope and you can read more about unique CodeDom features in Choosing Compiler Engine article.
Conclusion
This article briefly described the hosting API but you will find more samples in the downloadable package (on Releases page) in <cs-script>\samples\Hosting directory.
The hosting API itself is made compiler transparent so in terms of development effort it doesn't matter which compiler you use. However it doesn't mean that all compilers are offering the same functionality. The next article Choosing Compiler Engine will help you to chose the compiler most suitable for your task.

Updated Wiki: Hosted Script Execution

$
0
0
Related articles:

Hosted script execution

CS-Script can be hosted by any CLR application. The best way to bring scripting in your application is to add the corresponding NuGet package to your Visual Studio project :

Install-Package CS-Script.bin
or
Install-Package CS-Script 

'CS-Script.bin' package contains only binaries (e.g. CSScriptLibrary.dll) and 'CS-Script' contains binaries and sample files. The code samples in this article are consistent with the samples distributed with the NuGet package.

CSScriptLibrary.dll is the actual assembly implementing CS-Script as a class library. It is targeting .NET v4.0/4.5. However the package from the CodePlex Releases page always contains CSScriptLibrary.dll builds for earlier versions of .NET (<cs-script>\lib\Bin).
Setting up Evaluator
Any application hosting CS-Script engine can execute C# code containing either fully defined types or code fragments (e.g. methods). It is important to note that CS-Script is neither a compiler nor evaluator. It is rather a runtime environment that relies for the code compilation by the standard compiling toolset available with any .NET or Mono installation. The first compiling services CS-Script integrated was CodeDom. It is the very original compiler-as-service that was available starting from the first release of .NET.

While many may not consider CodeDom as 'true compiler-as-service', in reality, it actually is. The problem with CodeDom API is that it's inconvenient in require a great deal of manual runtime configuration. And it is exactly what CS-Script is addressing. Later on some alternative proprietary compiler-as-service solutions became available. First Mono Evaluator and later Roslyn (currently still Beta). Both demonstrated a completely different approach towards what good scripting API should look like. Thus all three compiling platforms are mutually inconsistent and only partially overlapping in with respect to functionality.

And this is where CS-Script comes to the rescue. It provides one unified generic interface transparent to the underlying compiler technology. You can have your script code executed by ether of three supported compilers without affecting your hosting code.

The code below demonstrates creating (compiling) a delegate.

var sqr = CSScript.Evaluator
                  .CreateDelegate(@"int Sqr(int a)
                                    {
                                        return a * a;
                                    }");
var r = sqr(3); 

By default CSScript.Evaluator references Mono compiler. However you can change this behavior globally by re-configuring the default compiler:

CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Mono;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Roslyn;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;

Alternatively you can access the corresponding compiler via a dedicated member property:

CSScript.MonoEvaluator.CreateDelegate(...
CSScript.RoslynEvaluator.CreateDelegate(...
CSScript.CodeDomEvaluator.CreateDelegate(...

Every time a CSScript.*Evaluator property is accessed a new instance of the corresponding evaluator is created and returned to the caller. Though this can be changed by re-configuring the evaluator access type to return the reference to the global evaluator object:

CSScript.EvaluatorConfig.Access = EvaluatorAccess.Singleton;


Executing the scripts
The evaluator allows executing code containing definition a type (or multiple types):

Assembly script = CSScript.Evaluator
                          .CompileCode(@"using System;
                                         public class Script
                                         {
                                             public int Sum(int a, int b)
                                             {
                                                 return a+b;
                                             }
                                         }");
         

Alternativelly you can compile code containing only method(s). In this case Evaluator will wrap the method code into a class definition with name DynamicClass:

Assembly script = CSScript.Evaluator
                          .CompileMethod(@"int Sum(int a, int b)
                                           {
                                               return a+b;
                                           }");
         

Further access to the script members can be simplified by using Evaluator.Load*, which compiles the code and returns the instance of the first class in compiled assembly:

dynamic script = CSScript.Evaluator
                         .LoadMethod(@"int Product(int a, int b)
                                       {
                                           return a * b;
                                       }");

int result = script.Product(3, 2);

Note that in the code below the method Product is invoked with 'dynamic' keyword, meaning that the host application cannot do any compile-time checking in the host code. In many cases it is oOK, though sometimes it is desirable that the script object was strongly typed. The easiest way to achieve this is to use interfaces:

publicinterface ICalc
{
    int Sum(int a, int b);
}
...
ICalc script = (ICalc)CSScript.Evaluator
                              .LoadCode(@"using System;
                                          public class Script : ICalc
                                          {
                                              public int Sum(int a, int b)
                                              {
                                                  return a+b;
                                              }
                                          }");
int result = script.Sum(1, 2);

Not that you can also use an Interface alignment (duck-typing) technique, which allows 'aligning' the script object to the interface even if it is not implementing this interface. It is achieved by evaluator wrapping the script object into dynamically generated proxy of the interface (e.g. ICals) type:

ICalc script = CSScript.Evaluator
                       .LoadCode<ICalc>(@"using System;
                                          public class Script
                                          {
                                              public int Sum(int a, int b)
                                              {
                                                  return a+b;
                                              }
                                          }");
      

Evaluator also allows compiling method scripts into class-less delegates:

var sqr = CSScript.Evaluator
                  .CreateDelegate<int>(@"int Sqr(int a)
                                         {
                                             return a * a;
                                         }");
int result = sqr(3); 

In the code above CreateDelegate returns MethodDelegate<T>, which is semi-dynamic by nature. It is strongly typed by return type and dynamically typed (thanks to 'params') by method parameters:

publicdelegate T MethodDelegate<T>(paramsobject[] paramters);

Though if strongly typed delegate is preferred then you can use LoadDelegate instead:

Func<int, int, int> product = CSScript.Evaluator
                                      .LoadDelegate<Func<int, int, int>>(
                                              @"int Product(int a, int b)
                                                {
                                                    return a * b;
                                                }");
int result = product(3, 2);

Script can automatically access all types of the host application without any restrictions according the types visibility (public vs. private). This is the evaluator by default references (for the script) all loaded assemblies of the current AppDomain. However custom assembly referencing is also available:

IEvaluator evaluator = CSScript.Evaluator;
string code = "<some C# code>";

evaluator.Reset(false); //clear all ref assemblies

evaluator.ReferenceAssembly(Assembly.GetExecutingAssembly())
         .ReferenceAssembly(@"c:\some_dir\myAsm.dll")                         
         .ReferenceAssemblyByName("System.Xml")                         
         .ReferenceAssemblyByNamespace("System.Windows.Forms")
         .ReferenceAssemblyOf(this)                         
         .ReferenceAssemblyOf<string>()                         
         .ReferenceAssembliesFromCode(code)
         .ReferenceDomainAssemblies();  
         
dynamic script = evaluator.LoadCode(code);

The code above is a pseudo code that is not particularly useful but it does demonstrates the referencing technique very well.
Method ReferenceAssembliesFromCode is particularly interesting as it utilizes CS-Script ability to analyse script code and find out what assemblies the script needs to reference. Read this article for more details.

Maintainability
While all three supported compiling services normalized via Evaluator interface some of the critical features only available via dedicated Evaluators. Thus CodeDom Evaluator is a 'champion' of all compilers as no others can match its flexibility. Thus it is the only compiler platform that supports script debugging:

CSScript.EvaluatorConfig.DebugBuild = true;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;

dynamic script = CSScript.Evaluator
                            .LoadCode(@"using System;
                                        using System.Diagnostics;
                                        public class Script
                                        {
                                            public int Sum(int a, int b)
                                            {
                                                Debug.Assert(false, ""Testing CS-Script debugging..."");
                                                return a+b;
                                            }
                                        }");

var r = script.Sum(3, 4); //triggers the assertion

Another very important CodeDom feature that is not available with other compilers is the ability to unload already loaded scripts. Though it is outside of this article scope and you can read more about unique CodeDom features in Choosing Compiler Engine article.
Conclusion
This article briefly described the hosting API but you will find more samples in the downloadable package (on Releases page) in <cs-script>\samples\Hosting directory.
The hosting API itself is made compiler transparent so in terms of development effort it doesn't matter which compiler you use. However it doesn't mean that all compilers are offering the same functionality. The next article Choosing Compiler Engine will help you to chose the compiler most suitable for your task.

Updated Wiki: Overview

$
0
0
Related articles:

CS-Script Overview

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);

Script standalone execution

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)

Hosted script execution

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.

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:

publicinterface 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.

Updated Wiki: Overview

$
0
0
Related articles:

CS-Script Overview

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);

Standalone script execution

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)

Hosted script execution

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.

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:

publicinterface 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.

Updated Wiki: Overview

$
0
0
Further reading:

CS-Script Overview

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);

Standalone script execution

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)

Hosted script execution

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.

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:

publicinterface 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.

Updated Wiki: Hosted Script Execution

$
0
0
Further reading:

Hosted script execution

CS-Script can be hosted by any CLR application. The best way to bring scripting in your application is to add the corresponding NuGet package to your Visual Studio project :

Install-Package CS-Script.bin
or
Install-Package CS-Script 

'CS-Script.bin' package contains only binaries (e.g. CSScriptLibrary.dll) and 'CS-Script' contains binaries and sample files. The code samples in this article are consistent with the samples distributed with the NuGet package.

CSScriptLibrary.dll is the actual assembly implementing CS-Script as a class library. It is targeting .NET v4.0/4.5. However the package from the CodePlex Releases page always contains CSScriptLibrary.dll builds for earlier versions of .NET (<cs-script>\lib\Bin).
Setting up Evaluator
Any application hosting CS-Script engine can execute C# code containing either fully defined types or code fragments (e.g. methods). It is important to note that CS-Script is neither a compiler nor evaluator. It is rather a runtime environment that relies for the code compilation by the standard compiling toolset available with any .NET or Mono installation. The first compiling services CS-Script integrated was CodeDom. It is the very original compiler-as-service that was available starting from the first release of .NET.

While many may not consider CodeDom as 'true compiler-as-service', in reality, it actually is. The problem with CodeDom API is that it's inconvenient in require a great deal of manual runtime configuration. And it is exactly what CS-Script is addressing. Later on some alternative proprietary compiler-as-service solutions became available. First Mono Evaluator and later Roslyn (currently still Beta). Both demonstrated a completely different approach towards what good scripting API should look like. Thus all three compiling platforms are mutually inconsistent and only partially overlapping in with respect to functionality.

And this is where CS-Script comes to the rescue. It provides one unified generic interface transparent to the underlying compiler technology. You can have your script code executed by ether of three supported compilers without affecting your hosting code.

The code below demonstrates creating (compiling) a delegate.

var sqr = CSScript.Evaluator
                  .CreateDelegate(@"int Sqr(int a)
                                    {
                                        return a * a;
                                    }");
var r = sqr(3); 

By default CSScript.Evaluator references Mono compiler. However you can change this behavior globally by re-configuring the default compiler:

CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Mono;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Roslyn;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;

Alternatively you can access the corresponding compiler via a dedicated member property:

CSScript.MonoEvaluator.CreateDelegate(...
CSScript.RoslynEvaluator.CreateDelegate(...
CSScript.CodeDomEvaluator.CreateDelegate(...

Every time a CSScript.*Evaluator property is accessed a new instance of the corresponding evaluator is created and returned to the caller. Though this can be changed by re-configuring the evaluator access type to return the reference to the global evaluator object:

CSScript.EvaluatorConfig.Access = EvaluatorAccess.Singleton;


Executing the scripts
The evaluator allows executing code containing definition a type (or multiple types):

Assembly script = CSScript.Evaluator
                          .CompileCode(@"using System;
                                         public class Script
                                         {
                                             public int Sum(int a, int b)
                                             {
                                                 return a+b;
                                             }
                                         }");
         

Alternativelly you can compile code containing only method(s). In this case Evaluator will wrap the method code into a class definition with name DynamicClass:

Assembly script = CSScript.Evaluator
                          .CompileMethod(@"int Sum(int a, int b)
                                           {
                                               return a+b;
                                           }");
         

Further access to the script members can be simplified by using Evaluator.Load*, which compiles the code and returns the instance of the first class in compiled assembly:

dynamic script = CSScript.Evaluator
                         .LoadMethod(@"int Product(int a, int b)
                                       {
                                           return a * b;
                                       }");

int result = script.Product(3, 2);

Note that in the code below the method Product is invoked with 'dynamic' keyword, meaning that the host application cannot do any compile-time checking in the host code. In many cases it is oOK, though sometimes it is desirable that the script object was strongly typed. The easiest way to achieve this is to use interfaces:

publicinterface ICalc
{
    int Sum(int a, int b);
}
...
ICalc script = (ICalc)CSScript.Evaluator
                              .LoadCode(@"using System;
                                          public class Script : ICalc
                                          {
                                              public int Sum(int a, int b)
                                              {
                                                  return a+b;
                                              }
                                          }");
int result = script.Sum(1, 2);

Not that you can also use an Interface alignment (duck-typing) technique, which allows 'aligning' the script object to the interface even if it is not implementing this interface. It is achieved by evaluator wrapping the script object into dynamically generated proxy of the interface (e.g. ICals) type:

ICalc script = CSScript.Evaluator
                       .LoadCode<ICalc>(@"using System;
                                          public class Script
                                          {
                                              public int Sum(int a, int b)
                                              {
                                                  return a+b;
                                              }
                                          }");
      

Evaluator also allows compiling method scripts into class-less delegates:

var sqr = CSScript.Evaluator
                  .CreateDelegate<int>(@"int Sqr(int a)
                                         {
                                             return a * a;
                                         }");
int result = sqr(3); 

In the code above CreateDelegate returns MethodDelegate<T>, which is semi-dynamic by nature. It is strongly typed by return type and dynamically typed (thanks to 'params') by method parameters:

publicdelegate T MethodDelegate<T>(paramsobject[] paramters);

Though if strongly typed delegate is preferred then you can use LoadDelegate instead:

Func<int, int, int> product = CSScript.Evaluator
                                      .LoadDelegate<Func<int, int, int>>(
                                              @"int Product(int a, int b)
                                                {
                                                    return a * b;
                                                }");
int result = product(3, 2);

Script can automatically access all types of the host application without any restrictions according the types visibility (public vs. private). This is the evaluator by default references (for the script) all loaded assemblies of the current AppDomain. However custom assembly referencing is also available:

IEvaluator evaluator = CSScript.Evaluator;
string code = "<some C# code>";

evaluator.Reset(false); //clear all ref assemblies

evaluator.ReferenceAssembly(Assembly.GetExecutingAssembly())
         .ReferenceAssembly(@"c:\some_dir\myAsm.dll")                         
         .ReferenceAssemblyByName("System.Xml")                         
         .ReferenceAssemblyByNamespace("System.Windows.Forms")
         .ReferenceAssemblyOf(this)                         
         .ReferenceAssemblyOf<string>()                         
         .ReferenceAssembliesFromCode(code)
         .ReferenceDomainAssemblies();  
         
dynamic script = evaluator.LoadCode(code);

The code above is a pseudo code that is not particularly useful but it does demonstrates the referencing technique very well.
Method ReferenceAssembliesFromCode is particularly interesting as it utilizes CS-Script ability to analyse script code and find out what assemblies the script needs to reference. Read this article for more details.

Maintainability
While all three supported compiling services normalized via Evaluator interface some of the critical features only available via dedicated Evaluators. Thus CodeDom Evaluator is a 'champion' of all compilers as no others can match its flexibility. Thus it is the only compiler platform that supports script debugging:

CSScript.EvaluatorConfig.DebugBuild = true;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;

dynamic script = CSScript.Evaluator
                            .LoadCode(@"using System;
                                        using System.Diagnostics;
                                        public class Script
                                        {
                                            public int Sum(int a, int b)
                                            {
                                                Debug.Assert(false, ""Testing CS-Script debugging..."");
                                                return a+b;
                                            }
                                        }");

var r = script.Sum(3, 4); //triggers the assertion

Another very important CodeDom feature that is not available with other compilers is the ability to unload already loaded scripts. Though it is outside of this article scope and you can read more about unique CodeDom features in Choosing Compiler Engine article.
Conclusion
This article briefly described the hosting API but you will find more samples in the downloadable package (on Releases page) in <cs-script>\samples\Hosting directory.
The hosting API itself is made compiler transparent so in terms of development effort it doesn't matter which compiler you use. However it doesn't mean that all compilers are offering the same functionality. The next article Choosing Compiler Engine will help you to chose the compiler most suitable for your task.

Updated Wiki: Choosing Compiler Engine

$
0
0

Compiler technology comparison.

CS-Script allows hosting/executing the scripts being compiled by any of the three supported compilers: CodeDom, Mono and Roslyn. Thanks to generic interface CS-Script offers identical developer experience for all these three compilers. However the compilers themselves are not entirely identical. The choice of the underlying compiler technology my affect runtime behavior and maintainability of the hosting solution.

The initial CS-Script hosting model was based on CodeDom compilation and support for Mono and Roslyn was added much later when these technologies became available. Naturally the CodeDom based API is not 100% aligned with the Mono and Roslyn native API. In fact the native API of the all three compilers are extremely inconsistent. They are so inconsistent that it was quite a challenge to define a common interface that can reconcile all the differences.

This challenge has bee answered and today the main hosting interface can be accessed via CSScript.Evaluator property (e.g. CSScript.Evaluator.LoadCode(..)). It is the entry point for the all three compilers and this is the API that you should rely on in most of the cases. This common interface referred through all the documentation as CSScript.Evaluator.

The original native CodeDom-only interface is still available. And it can be accessed via direct members of the CSScript class (e.g. CSScript.LoadCode(..)). This CodeDom specific interface referred through all the documentation as CSScript.Native. This interface is provided for legacy reasons and to allow the access to the CodeDom specific functionality no available with CSScript.Evaluator.

CSScript.Native

CSScript.Native and CSScript.Evaluator share a great deal of similarities though you need to remember CSScript.Evaluator is the later arrival and as such it represents the result of a more thought through design. Meaning that by default you should use CSScript.Evaluator and CSScript.Native should be reserved for the cases when CSScript.Evaluator functionality is insufficient.

The following is an example of creating a delegate object from a method definition code with CSScript.Native:

var sayHello = CSScript.LoadDelegate<Action<string>>(
                                    @"void SayHello(string greeting)
                                      {
                                          Console.WriteLine(greeting);
                                      }");

sayHello("Hello World!");

And this is the similar task done with CSScript.Evaluator:

var product = CSScript.Evaluator
                      .LoadDelegate<Func<int, int, int>>(
                                  @"int Product(int a, int b)
                                    {
                                        return a * b;
                                    }");

int result = product(3, 2);

CSScript.Evaluator

CSScript.Evaluator exposes the scripting functionality, which is common for all supported compilers. The section below will explain certain runtime differences between the compilers.

CodeDom compiler

CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;

CodeDom is all about dynamically emitting the assemblies defined by collection of the runtime objects (code DOM objects) and only small part of CodeDom is dedicated for building assemblies defined by the text (code). Only this part is used by CS-Script. CodeDom is very well suitable for dealing with larger pieces of code representing a complete task/job (file or collection of files). Thus it naturally fits the role of a script compiler.
Advantages
  • It is mature. It is in fact the most utilized and tested over the years compiling platform of CS-Script.
  • The most important one: CodeDom emits file-based assemblies. Meaning that it also generates debug symbols. This in turn allows debugging the scripts.
  • By being native part of the CS-Script engine CodeDom supports all CS-Script code directives (e.g. //css_include).
  • The compiled scripts assemblies can be referenced by other scripts (thanks to the file-based assemblies).
  • Compiler loading is subject of CS-Script dependency-injection policy thus you can take advantage of the 'Alternative Compiler' feature. Meaning that it is possible to evaluate the script written in non-C# syntax (e.g. VB).
  • All scripts are automatically subject of CS-Script caching. This prevents script code being compiled more than once. Doesn't matter how many times you execute the script a given unique script code will always be evaluated only once. This in turn leads to an enormous performance bust. But of course it is the case only if the scripts are being executed multiple times are not changed between executions.
DisAdvantages
  • C# 6 syntax for scripts is not available out of box. It is hard to believe but Microsoft did not released C# 6 compiler with .NET 4.6. Though the work around is relatively simple. You just need to provide the path to teh Instead they delegated compiling to custom compiler for C# 6. If you have CS-Script present then it is only a single line of code:
    CSScript.GlobalSettings.UseAlternativeCompiler = @"%CSSCRIPT_DIR%\Lib\CSSCodeProvider.v4.6.dll"; 
  • CodeDom provides a compiler-as-service experience but under the hood it does create some temporary files and these IO operations do not go unnoticed for the performance. This makes CodeDom the slowest of all three compilers. Automatic caching partially compensates the performance loses.

Mono compiler

CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Mono; 

Mono is a true in-memory compiler. Fast, mature, reliable. The native interface of Mono Evaluator is a little unorthodox but because it is accessed via CSScript generic interface there is no any usability impact.
Advantages
  • It is mature.
  • It is fast. Much faster than CodeDom as all operations are in-memory tasks.
  • It is light. Just a single dll (included in CS-Script distro).
Disadvantages
  • The compiled scripts are in-memory assemblies. Meaning that they cannot be debugged. There is no any work around.
  • Mono Evaluator doesn't support C# 6 syntax (at least v4.0.0.0). There is no any work around.

Roslyn compiler

CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Roslyn; 

Roslyn is another true in-memory compiler. It is fast (code evaluation only) and has a reasonably comfortable native interface, which is anyway normalized by the common CSScript.Evaluator. The biggest problem of Roslyn is that it is still not out of beta (v1.2.0-beta-20151211-01).
Advantages
  • It is fast. Practically as fast as Mono.
  • Support C# 6 syntax straight out of box.
Disadvantages
  • It is still in development. Its native interface can change any time and break CS-Script integration. To address this CS-Script is distributed with the full set of Roslyn assemblies.
  • It is heavy.
    • The very first call to can take up to 5 seconds to initialize the compiler infrastructure.
    • You need to reference 6.5M of 8 assemblies in total(included in CS-Script distro).
    • Compiling time is heavily affected by number of ref assemblies (Mono doesn't exhibit such a behaviour)
  • The compiled scripts are in-memory assemblies. Meaning that they cannot be debugged. There is no any work around.
  • Script cannot have namespaces. There is no any work around.
  • The compiled scripts cannot be referenced by other scripts. The only work around it to reuse the same evaluator instance.
  • All script types are compiled as nested classes.
  • Everything (e.g. class code) is compiled as a nested class with the parent class name "Submission#N" and the number-sign makes it extremely difficult to reference the type from other scripts


Updated Wiki: Choosing Compiler Engine

$
0
0

Compiler technology comparison.

CS-Script allows hosting/executing the scripts being compiled by any of the three supported compilers: CodeDom, Mono and Roslyn. Thanks to generic interface CS-Script offers identical developer experience for all these three compilers. However the compilers themselves are not entirely identical. The choice of the underlying compiler technology my affect runtime behavior and maintainability of the hosting solution.

The initial CS-Script hosting model was based on CodeDom compilation and support for Mono and Roslyn was added much later when these technologies became available. Naturally the CodeDom based API is not 100% aligned with the Mono and Roslyn native API. In fact the native API of the all three compilers are extremely inconsistent. They are so inconsistent that it was quite a challenge to define a common interface that can reconcile all the differences.

This challenge has bee answered and today the main hosting interface can be accessed via CSScript.Evaluator property (e.g. CSScript.Evaluator.LoadCode(..)). It is the entry point for the all three compilers and this is the API that you should rely on in most of the cases. This common interface referred through all the documentation as CSScript.Evaluator.

The original native CodeDom-only interface is still available. And it can be accessed via direct members of the CSScript class (e.g. CSScript.LoadCode(..)). This CodeDom specific interface referred through all the documentation as CSScript.Native. This interface is provided for legacy reasons and to allow the access to the CodeDom specific functionality no available with CSScript.Evaluator.

CSScript.Native

CSScript.Native and CSScript.Evaluator share a great deal of similarities though you need to remember CSScript.Evaluator is the later arrival and as such it represents the result of a more thought through design. Meaning that by default you should use CSScript.Evaluator and CSScript.Native should be reserved for the cases when CSScript.Evaluator functionality is insufficient.

The following is an example of creating a delegate object from a method definition code with CSScript.Native:

var sayHello = CSScript.LoadDelegate<Action<string>>(
                                    @"void SayHello(string greeting)
                                      {
                                          Console.WriteLine(greeting);
                                      }");

sayHello("Hello World!");

And this is the similar task done with CSScript.Evaluator:

var product = CSScript.Evaluator
                      .LoadDelegate<Func<int, int, int>>(
                                  @"int Product(int a, int b)
                                    {
                                        return a * b;
                                    }");

int result = product(3, 2);

CSScript.Evaluator

CSScript.Evaluator exposes the scripting functionality, which is common for all supported compilers. The section below will explain certain runtime differences between the compilers.

CodeDom compiler

CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;

CodeDom is all about dynamically emitting the assemblies defined by collection of the runtime objects (code DOM objects) and only small part of CodeDom is dedicated for building assemblies defined by the text (code). Only this part is used by CS-Script. CodeDom is very well suitable for dealing with larger pieces of code representing a complete task/job (file or collection of files). Thus it naturally fits the role of a script compiler.
Advantages
  • It is mature. It is in fact the most utilized and tested over the years compiling platform of CS-Script.
  • The most important one: CodeDom emits file-based assemblies. Meaning that it also generates debug symbols. This in turn allows debugging the scripts.
  • By being native part of the CS-Script engine CodeDom supports all CS-Script code directives (e.g. //css_include).
  • The compiled scripts assemblies can be referenced by other scripts (thanks to the file-based assemblies).
  • Compiler loading is subject of CS-Script dependency-injection policy thus you can take advantage of the 'Alternative Compiler' feature. Meaning that it is possible to evaluate the script written in non-C# syntax (e.g. VB).
  • All scripts are automatically subject of CS-Script caching. This prevents script code being compiled more than once. Doesn't matter how many times you execute the script a given unique script code will always be evaluated only once. This in turn leads to an enormous performance bust. But of course it is the case only if the scripts are being executed multiple times are not changed between executions.
DisAdvantages
  • C# 6 syntax for scripts is not available out of box. It is hard to believe but Microsoft did not released C# 6 compiler with .NET 4.6. Though the work around is relatively simple. You just need to provide the path to teh Instead they delegated compiling to custom compiler for C# 6. If you have CS-Script present then it is only a single line of code:
    CSScript.GlobalSettings.UseAlternativeCompiler = 
                        "%CSSCRIPT_DIR%\Lib\CSSCodeProvider.v4.6.dll"; 
  • CodeDom provides a compiler-as-service experience but under the hood it does create some temporary files and these IO operations do not go unnoticed for the performance. This makes CodeDom the slowest of all three compilers. Automatic caching partially compensates the performance loses.

Mono compiler

CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Mono; 

Mono is a true in-memory compiler. Fast, mature, reliable. The native interface of Mono Evaluator is a little unorthodox but because it is accessed via CSScript generic interface there is no any usability impact.
Advantages
  • It is mature.
  • It is fast. Much faster than CodeDom as all operations are in-memory tasks.
  • It is light. Just a single dll (included in CS-Script distro).
Disadvantages
  • The compiled scripts are in-memory assemblies. Meaning that they cannot be debugged. There is no any work around.
  • Mono Evaluator doesn't support C# 6 syntax (at least v4.0.0.0). There is no any work around.

Roslyn compiler

CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Roslyn; 

Roslyn is another true in-memory compiler. It is fast (code evaluation only) and has a reasonably comfortable native interface, which is anyway normalized by the common CSScript.Evaluator. The biggest problem of Roslyn is that it is still not out of beta (v1.2.0-beta-20151211-01).
Advantages
  • It is fast. Practically as fast as Mono.
  • Support C# 6 syntax straight out of box.
Disadvantages
  • It is still in development. Its native interface can change any time and break CS-Script integration. To address this CS-Script is distributed with the full set of Roslyn assemblies.
  • It is heavy.
    • The very first call to can take up to 5 seconds to initialize the compiler infrastructure.
    • You need to reference 6.5M of 8 assemblies in total(included in CS-Script distro).
    • Compiling time is heavily affected by number of ref assemblies (Mono doesn't exhibit such a behaviour)
  • The compiled scripts are in-memory assemblies. Meaning that they cannot be debugged. There is no any work around.
  • Script cannot have namespaces. There is no any work around.
  • The compiled scripts cannot be referenced by other scripts. The only work around it to reuse the same evaluator instance.
  • All script types are compiled as nested classes.
  • Everything (e.g. class code) is compiled as a nested class with the parent class name "Submission#N" and the number-sign makes it extremely difficult to reference the type from other scripts


Updated Wiki: Hosted Script Execution

$
0
0
Further reading:

Hosted script execution

CS-Script can be hosted by any CLR application. The best way to bring scripting in your application is to add the corresponding NuGet package to your Visual Studio project :

Install-Package CS-Script.bin
or
Install-Package CS-Script 

'CS-Script.bin' package contains only binaries (e.g. CSScriptLibrary.dll) and 'CS-Script' contains binaries and sample files. The code samples in this article are consistent with the samples distributed with the NuGet package.

CSScriptLibrary.dll is the actual assembly implementing CS-Script as a class library. It is targeting .NET v4.0/4.5. However the package from the CodePlex Releases page always contains CSScriptLibrary.dll builds for earlier versions of .NET (<cs-script>\lib\Bin).
Setting up Evaluator
Any application hosting CS-Script engine can execute C# code containing either fully defined types or code fragments (e.g. methods). It is important to note that CS-Script is neither a compiler nor evaluator. It is rather a runtime environment that relies for the code compilation by the standard compiling toolset available with any .NET or Mono installation. The first compiling services CS-Script integrated was CodeDom. It is the very original compiler-as-service that was available starting from the first release of .NET.

While many may not consider CodeDom as 'true compiler-as-service', in reality, it actually is. The problem with CodeDom API is that it's inconvenient in require a great deal of manual runtime configuration. And it is exactly what CS-Script is addressing. Later on some alternative proprietary compiler-as-service solutions became available. First Mono Evaluator and later Roslyn (currently still Beta). Both demonstrated a completely different approach towards what good scripting API should look like. Thus all three compiling platforms are mutually inconsistent and only partially overlapping in with respect to functionality.

And this is where CS-Script comes to the rescue. It provides one unified generic interface transparent to the underlying compiler technology. You can have your script code executed by ether of three supported compilers without affecting your hosting code.

The code below demonstrates creating (compiling) a delegate.

var sqr = CSScript.Evaluator
                  .CreateDelegate(@"int Sqr(int a)
                                    {
                                        return a * a;
                                    }");
var r = sqr(3); 

By default CSScript.Evaluator references Mono compiler. However you can change this behavior globally by re-configuring the default compiler:

CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Mono;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Roslyn;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;

Alternatively you can access the corresponding compiler via a dedicated member property:

CSScript.MonoEvaluator.CreateDelegate(...
CSScript.RoslynEvaluator.CreateDelegate(...
CSScript.CodeDomEvaluator.CreateDelegate(...

Every time a CSScript.*Evaluator property is accessed a new instance of the corresponding evaluator is created and returned to the caller. Though this can be changed by re-configuring the evaluator access type to return the reference to the global evaluator object:

CSScript.EvaluatorConfig.Access = EvaluatorAccess.Singleton;


Executing the scripts
The evaluator allows executing code containing definition a type (or multiple types):

Assembly script = CSScript.Evaluator
                          .CompileCode(@"using System;
                                         public class Script
                                         {
                                             public int Sum(int a, int b)
                                             {
                                                 return a+b;
                                             }
                                         }");
         

Alternativelly you can compile code containing only method(s). In this case Evaluator will wrap the method code into a class definition with name DynamicClass:

Assembly script = CSScript.Evaluator
                          .CompileMethod(@"int Sum(int a, int b)
                                           {
                                               return a+b;
                                           }");
         

Further access to the script members can be simplified by using Evaluator.Load*, which compiles the code and returns the instance of the first class in compiled assembly:

dynamic script = CSScript.Evaluator
                         .LoadMethod(@"int Product(int a, int b)
                                       {
                                           return a * b;
                                       }");

int result = script.Product(3, 2);

Note that in the code below the method Product is invoked with 'dynamic' keyword, meaning that the host application cannot do any compile-time checking in the host code. In many cases it is oOK, though sometimes it is desirable that the script object was strongly typed. The easiest way to achieve this is to use interfaces:

publicinterface ICalc
{
    int Sum(int a, int b);
}
...
ICalc script = (ICalc)CSScript.Evaluator
                              .LoadCode(@"using System;
                                          public class Script : ICalc
                                          {
                                              public int Sum(int a, int b)
                                              {
                                                  return a+b;
                                              }
                                          }");
int result = script.Sum(1, 2);

Not that you can also use an Interface alignment (duck-typing) technique, which allows 'aligning' the script object to the interface even if it is not implementing this interface. It is achieved by evaluator wrapping the script object into dynamically generated proxy of the interface (e.g. ICals) type:

ICalc script = CSScript.Evaluator
                       .LoadCode<ICalc>(@"using System;
                                          public class Script
                                          {
                                              public int Sum(int a, int b)
                                              {
                                                  return a+b;
                                              }
                                          }");
      

Evaluator also allows compiling method scripts into class-less delegates:

var sqr = CSScript.Evaluator
                  .CreateDelegate<int>(@"int Sqr(int a)
                                         {
                                             return a * a;
                                         }");
int result = sqr(3); 

In the code above CreateDelegate returns MethodDelegate<T>, which is semi-dynamic by nature. It is strongly typed by return type and dynamically typed (thanks to 'params') by method parameters:

publicdelegate T MethodDelegate<T>(paramsobject[] paramters);

Though if strongly typed delegate is preferred then you can use LoadDelegate instead:

Func<int, int, int> product = CSScript.Evaluator
                                      .LoadDelegate<Func<int, int, int>>(
                                              @"int Product(int a, int b)
                                                {
                                                    return a * b;
                                                }");
int result = product(3, 2);

Script can automatically access all types of the host application without any restrictions according the types visibility (public vs. private). This is the evaluator by default references (for the script) all loaded assemblies of the current AppDomain. However custom assembly referencing is also available:

IEvaluator evaluator = CSScript.Evaluator;
string code = "<some C# code>";

evaluator.Reset(false); //clear all ref assemblies

evaluator.ReferenceAssembly(Assembly.GetExecutingAssembly())
         .ReferenceAssembly(@"c:\some_dir\myAsm.dll")                         
         .ReferenceAssemblyByName("System.Xml")                         
         .ReferenceAssemblyByNamespace("System.Windows.Forms")
         .ReferenceAssemblyOf(this)                         
         .ReferenceAssemblyOf<string>()                         
         .ReferenceAssembliesFromCode(code)
         .ReferenceDomainAssemblies();  
         
dynamic script = evaluator.LoadCode(code);

The code above is a pseudo code that is not particularly useful but it does demonstrates the referencing technique very well.
Method ReferenceAssembliesFromCode is particularly interesting as it utilizes CS-Script ability to analyse script code and find out what assemblies the script needs to reference. Read this article for more details.

Maintainability
While all three supported compiling services normalized via Evaluator interface some of the critical features only available via dedicated Evaluators. Thus CodeDom Evaluator is a 'champion' of all compilers as no others can match its flexibility. Thus it is the only compiler platform that supports script debugging:

CSScript.EvaluatorConfig.DebugBuild = true;
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;

dynamic script = CSScript.Evaluator
                         .LoadCode(@"using System;
                                     using System.Diagnostics;
                                     public class Script
                                     {
                                         public int Sum(int a, int b)
                                         {
                                             Debug.Assert(false, ""Testing..."");
                                             return a+b;
                                         }
                                     }");

var r = script.Sum(3, 4); //triggers the assertion

Another very important CodeDom feature that is not available with other compilers is the ability to unload already loaded scripts. Though it is outside of this article scope and you can read more about unique CodeDom features in Choosing Compiler Engine article.
Conclusion
This article briefly described the hosting API but you will find more samples in the downloadable package (on Releases page) in <cs-script>\samples\Hosting directory.
The hosting API itself is made compiler transparent so in terms of development effort it doesn't matter which compiler you use. However it doesn't mean that all compilers are offering the same functionality. The next article Choosing Compiler Engine will help you to chose the compiler most suitable for your task.

Updated Wiki: Documentation

$
0
0
For online help and other product related information please visitCS-Script Home Page.The help content can also be downloaded form Releases page.
Further reading:

CS-Script Overview

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);

Script stand alone execution

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.

Hosted script execution

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.

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:

publicinterface 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.

Source code checked in, #a5eb058ee59082775f072154886f12319f23733f

Source code checked in, #65f2ce5371f4b13fb336cf04b65dd79cc47c9203

$
0
0
CSSCript.Evaluator extensions UTests

Source code checked in, #ba9b1de78bd06a972ed14bda6f16cc23a4d81b33

$
0
0
CSSCript.Evaluator extensions UTests (WIP)

Updated Wiki: .NET 4.6 Support

$
0
0

Support for C#6.0 support

Usage

Starting from v3.9.15 CS-Script does support execution of C# 6.0 scripts. However due to the unstable (and slow) nature of the current MS solution for C# 6.0 hosted compilation it is disabled by default.

If you want to enable it you need set CSSCodeProvider.v.4.6.dll as your CS-Script code compiler. You can do this either globally via configuration console (not recommended) or per script with //css_args directive:
//css_args /provider:%CSSCRIPT_DIR%\lib\CSSCodeProvider.v4.6.dll using System;

class Script
{
    staticvoid Main(string[] args)
    {
        int count = 333;
        Console.WriteLine($"Count: {count}");
    }
}
Global configuration

Background

Unfortunately due to the MS shocking decision not to implement C# 6.0 dynamic compilation with CodeDOM this feature was very difficult to implement in CS-Script.

The problem is due to the fact that MS decided not to distribute any more Microsoft.CodeDom.Providers for C# (6.0) after doing this for the last 15 years for early versions. You've hired right. If in your application (built with C# 6.0) you use CodeDOM C# compiler for building the assembly from the C# source it will not allow v6.0 syntax but only v5.0.

For people who needs C# 6.0 compilation MS advises using NuGet package (CodeDOM Providers for .NET Compiler Platform ("Roslyn")) instead. Leaving along the deployment implications the package doesn't work just out of box. Meaning that today there is no a solid working solution for C# 6.0 hosted compilation.

Roslyn CSharpCodeProvider throws the error "cannot find csc.exe". After some experiments and analysis of Roslyn sources I found that it uses hard-codded csc.exe path. And this path is a relative one but not to the current directory but to the AppDomain.CurrentDomain.BaseDirectory!!!! Meaning that nothing you can do to change it.

MS's CompilationSettings.cs
internalstaticclass CompilationSettingsHelper {
    privatestatic ICompilerSettings _csc = new CompilerSettings(CompilerFullPath(@"bin\roslyn\csc.exe"), DefaultCompilerServerTTL);
    ... 
    privatestaticstring CompilerFullPath(string relativePath) {
        string compilerFullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, relativePath);
        return compilerFullPath;
    }
}

There is a CompilerSettings class that supposed to allow customization of the complete compiler path but it pedantically made private so no one can use it. Brilliant!

In order to solve the problem one has to use reflection to actually fix the compiler path. This is how CS-Script does it:

using roslyn=Microsoft.CodeDom.Providers.DotNetCompilerPlatform;

staticclass RoslynExtensions
{
    publicstaticvoid SetCompilerPath(this roslyn.CSharpCodeProvider provider, string path)
    {
        var flags = BindingFlags.NonPublic | BindingFlags.Instance;
        var settings = provider.GetType()
                               .GetField("_compilerSettings", flags)
                               .GetValue(provider);
        settings.GetType()
                .GetField("_compilerFullPath", flags)
                .SetValue(settings, path);
    }
}

And to make thing worth, the compilation using NuGet package CodeDOM providers is significantly slower then using standard providers for early versions of C#.

Of course Roslyn team will eventually fix these mistakes but it is very disappointing nevertheless as it does confirm that Roslyn isn't fully matured yet. Even after being 6 years in making.

Updated Wiki: Standalone Script Execution

$
0
0

Script stand alone execution

Script stand alone execution is the most mature and stable part of CS-Script feature set. Thus the major online documentation has been written quite some time ago and while it may currently have some referencing discrepancies (e.g. VS2012 instead of VS2015) it is still an accurate primary source of CS-Script knowledge. This Wiki article on the other hand is the most concise and concentrated description of the relevant content and in many cases it will be fully sufficient for majority of the readers. In all other cases please refer to the primary Documentation online.

CS-Script allows a direct single step execution of files containing ECMA-compliant C# code. The script engine executable comes in three forms:
  • cscs.exe - console application executable
  • csws.exe - Windows application executable
  • css.exe - Universal executable. It launches cscs.exe and makes console window visible on the first console output from the script being executed.
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.
Thus the minimal deployment file set for CS-Script is either cscs.exe or csws.exe file. Any of these files is sufficient for the wast majority of the scripting scenarios.

Installing CS-Script environment

The simplest way to start using CS-Script is to install it from Chocolatey, which is a repository for the Windows software packages. Chocolatey it is a Windows version of Linux apt-get. CS-Script_ can be installed with the following command:
```
C:\> choco install cs-script
```
During the installation Chocolatey downloads the latest version of CS-Script (from the official releases repository), extracts all files in the default Chocolatey libraries location and executes CS-Script's cssconfig.exe, which configures the OS for running C# scripts. Strictly speaking running cssconfig.exe is optional. The only thing that it does is adding the CS-Script location to the system PATH, and adds Windows Explorer shell extensions (context menu).

Deploying C# scripts

Any OS that have .NET/Mono installed can run C# scripts. The minimal distribution file set is the script engine executable and the script file itself. Of course if the script depends on the third-party library or other scripts then they also need to be deployed on the target system. The easiest way of preparing the script for running on another system is to use Notepad++ with C# Intellisense plugin enabled. Just click the "distro" button and the plugin will analyse the script and package it with all its dependencies along with the script engine itself. Optionally it may convert the script into a self sufficient single executable.
Cannot resolve image macro, invalid image name or id.

Features

From the start CS-Script was heavily influenced by Python and the developer experiences it delivers. Thus the it tries to match the most useful Python features (apart from the Python syntax). Here are some highlight of the CS-Script features. Some more info can be found here.
  • Scripts are written in 'plain vanilla' CLS-compliant C#. Though classless scripts are also supported.
  • Remarkable execution speed matching performance of compiled managed applications.
  • 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.
  • Building a self sufficient executable from the script.
  • 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 plugin for Notepad++ brings true Intellisense to the 'peoples editor')

Quick guide of CS-Script directives

CS-Script relies on so called 'script directives' for implementing some features. These directives are the C# comments that do not abstract standard C# compilers and yet provide user defined instructions for the script engine. Set of supported directives is very small set of commend. The full description with code samples can be found here. The following is a cheat sheet on script directives:
url//css_inc - import/include another C# script (similar to C++ #include).
url//css_ref - reference .NET assembly.
url//css_args - provide startup arguments.
url//css_dir - set additional probing directories for dependency scripts and assemblies.
url//css_nuget - reference (and download if not present) NuGet package.
Note, due to the fact that Microsoft stopped distributing the latest C# compiler with it's .NET deployment, support for C# 6.0 syntax requires one extra step to be done. You will need to indicate the location of the Roslyn compiler (deployed with CS-Script) either globally or per-script. Read more about it here.

Editing scripts

The scripts can be edited with any suitable text editor. Though if want to take advantage of Intellisense you may prefer Visual Studio with CS-Script extension. The extension can be enabled via VS Extension Manager.
Though in many cases you may be better off with just Notepad++. You will need to enable C# intellisense plugin from the plugin manager. THis plugin was developed specifically to allow VS-like experience when dealing with C# scripts and any C# code. The plugin comes with it's own CS-Script package and allows true C# Intellisence assisted editing as well as the execution and debugging.

Updated Wiki: Standalone Script Execution

$
0
0
Further reading:

Script stand alone execution

Script stand alone execution is the most mature and stable part of CS-Script feature set. Thus the major online documentation has been written quite some time ago and while it may currently have some referencing discrepancies (e.g. VS2012 instead of VS2015) it is still an accurate primary source of CS-Script knowledge. This Wiki article on the other hand is the most concise and concentrated description of the relevant content and in many cases it will be fully sufficient for majority of the readers. In all other cases please refer to the primary Documentation online.

CS-Script allows a direct single step execution of files containing ECMA-compliant C# code. The script engine executable comes in three forms:
  • cscs.exe - console application executable
  • csws.exe - Windows application executable
  • css.exe - Universal executable. It launches cscs.exe and makes console window visible on the first console output from the script being executed.
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.
Thus the minimal deployment file set for CS-Script is either cscs.exe or csws.exe file. Any of these files is sufficient for the wast majority of the scripting scenarios.

Installing CS-Script environment

The simplest way to start using CS-Script is to install it from Chocolatey, which is a repository for the Windows software packages. Chocolatey it is a Windows version of Linux apt-get. CS-Script can be installed with the following command:
C:\> choco install cs-script
During the installation Chocolatey downloads the latest version of CS-Script (from the official releases repository), extracts all files in the default Chocolatey libraries location and executes CS-Script's cssconfig.exe, which configures the OS for running C# scripts. Strictly speaking running cssconfig.exe is optional. The only thing that it does is adding the CS-Script location to the system PATH, and adds Windows Explorer shell extensions (context menu).

Deploying C# scripts

Any OS that have .NET/Mono installed can run C# scripts. The minimal distribution file set is the script engine executable and the script file itself. Of course if the script depends on the third-party library or other scripts then they also need to be deployed on the target system. The easiest way of preparing the script for running on another system is to use Notepad++ with C# Intellisense plugin enabled. Just click the "distro" button and the plugin will analyse the script and package it with all its dependencies along with the script engine itself. Optionally it may convert the script into a self sufficient single executable.

Features

From the start CS-Script was heavily influenced by Python and the developer experiences it delivers. Thus the it tries to match the most useful Python features (apart from the Python syntax). Here are some highlight of the CS-Script features. Some more info can be found here.
  • Scripts are written in 'plain vanilla' CLS-compliant C#. Though classless scripts are also supported.
  • Remarkable execution speed matching performance of compiled managed applications.
  • 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.
  • Building a self sufficient executable from the script.
  • 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 plugin for Notepad++ brings true Intellisense to the 'peoples editor')

Quick guide of CS-Script directives

CS-Script relies on so called 'script directives' for implementing some features. These directives are the C# comments that do not abstract standard C# compilers and yet provide user defined instructions for the script engine. Set of supported directives is very small set of commend. The full description with code samples can be found here. The following is a cheat sheet on script directives:
url//css_inc - import/include another C# script (similar to C++ #include).
url//css_ref - reference .NET assembly.
url//css_args - provide startup arguments.
url//css_dir - set additional probing directories for dependency scripts and assemblies.
url//css_nuget - reference (and download if not present) NuGet package.
Note, due to the fact that Microsoft stopped distributing the latest C# compiler with it's .NET deployment, support for C# 6.0 syntax requires one extra step to be done. You will need to indicate the location of the Roslyn compiler (deployed with CS-Script) either globally or per-script. Read more about it here.

Editing scripts

The scripts can be edited with any suitable text editor. Though if want to take advantage of Intellisense you may prefer Visual Studio with CS-Script extension. The extension can be enabled via VS Extension Manager.
Though in many cases you may be better off with just Notepad++. You will need to enable C# intellisense plugin from the plugin manager. THis plugin was developed specifically to allow VS-like experience when dealing with C# scripts and any C# code. The plugin comes with it's own CS-Script package and allows true C# Intellisence assisted editing as well as the execution and debugging.

Updated Wiki: images

Viewing all 355 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>