FastScript .NET supports the following features of the C# language (the C# 1.0 specification is most fully supported, along with many features from later versions of the language):
C# 1.0:
● Classes
● Structs
● Enums
● Interfaces
● Events
● Operator overloading
● User-defined conversion operators
● Properties
● Indexers
● Output parameters—out, ref
● Params arrays
● Delegates
● Operators and expressions
● Verbatim identifier "@"
C# 2.0:
● Generics
● Partial types
● Nullable value types
● Getter/setter separate accessibility
● Static classes
C# 3.0:
● Auto-implemented properties
● Extension methods
● Implicitly typed local variables
C# 4.0:
● Optional arguments
C# 6.0:
● Auto-property initializers
● Properties and methods that return the "=>" expression (Expression bodied members)
● Null propagator
C# 7.0:
● Out variables
● Local functions
C# 8.0:
● The "readonly" modifier for fields (Readonly members)
● Static local functions
● Null-coalescing operators
C# 9.0:
● Top-level statements
The following features of C# 1.0 are not supported:
● Preprocessor directives - #if, #region, etc.
● Attributes
● Unmanaged code: pointers, unsafe keyword, P/Invoke
● checked, unchecked statements
● goto statement
The terms used below: "host" refers to your .NET application; "script" refers to something defined in the script code.
Classes defined in the script can be inherited from other script classes or from System.Object:
class MyScriptClass: OtherScriptClass // ok
class MyScriptClass: Object // ok
class MyScriptClass // ok, same as Object
class MyScriptClass: ArrayList // error
In FastScript, a structure is represented as a regular class. FastScript adds special methods for copying the structure when its value is passed to a method or assigned to another variable. Declaring a variable of a structure type does not automatically create an instance of the structure:
MyStruct s; // s is null
s = new MyStruct(); // and must be initialized before use
A class defined in the script is visible to the host as an instance of FastScript.Runtime.DataContext.
You can override the following methods in the script class:
● ToString
● Equals
● GetHashCode
These overridden methods will also take an effect if used by host.
A script class may implement some of host interfaces, but it has effect in a script only. Passing such an instance to a host will not work, the host will not be able to use interface members implemented in a script.
Nullable types can only be used with host types.
Only host generic types and methods can be used in the script. You cannot define a generic type or method in the script.
If a host type is marked as "forwarded," it must be explicitly used in the host for it to be usable in the script. For example:
var list = new System.ComponentModel.BindingList<int>(); // error, BindingList does not exist
If you add the following line of code to your application, the script will compile without errors:
new System.ComponentModel.BindingList<int>();
You can create delegates of any methods (script or host). Passing a delegate to host is not supported though. You also cannot create Action<> and Func<> delegates (these host classes require a native method with certain signature, which can't be done in a script).
User-defined type conversion (in script code or in the host) is limited to those types that are explicitly defined. For example, if a T->int conversion is defined, you can use it. However, you will not be able to use a T->float conversion unless it is explicitly defined.
var m = new My();
int intValue = m; // ok
float floatValue = m; // error
int explicitIntValue = (int)m; // ok: explicit is not defined, but we have implicit one
float explicitFloatValue = (float)m; // error
floatValue = (int)m; // use this way
public class My
{
private object _value;
public static implicit operator int(My m) => (int)m._value;
}
In the script, you can only use types that are available in the host. An application compiled in Native AOT mode may not include certain types (or members of types) that you would like to use in the script, because the type/member was trimmed from the assembly.
Another issue is the use of generic types/methods. In Native AOT, you can use those generic types that are available in the host. For example, if the host uses the class List <int>, but does not utilize the class List<double>. The first one can be used in the script, but an error will occur if you try to create a type List<double>.
Therefore, your task will be to make types (and members of types) statically available in your application so that they can be used in the script. This can be accomplished in various ways (creating instances of types, using attributes):
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(List<>))]
public void EnsureAOTVisible()
{
var list = new List<int>();
}
Note that generic parameters of reference types can be used if an open generic type is available in a host app. For example, having a List<> type available in your app, you may construct List<object> or List<List<...>> or List<Dictionary<...>>.