FastScript .NET unterstützt die folgenden Funktionen der C#-Sprache (die meisten werden von der C# 1.0-Spezifikation unterstützt, wobei viele Funktionen von späteren Versionen der Sprache hinzugefügt wurden):
C# 1.0:
● Klassen (Classes)
● Strukturen (Structures)
● Enumerationen (Enums)
● Schnittstellen (Interfaces)
● Ereignisse (Events)
● Operatorüberladung (Operator overloading)
● Benutzerdefinierte Konvertierungsoperatoren (User-defined conversion operators)
● Eigenschaften (Properties)
● Indexers
● Ausgabeparameter von Methoden (Output parameters - out, ref)
● Parameterarrays (Parameter arrays)
● Delegaten (Delegates)
● Operatoren und Ausdrücke (Operators and expressions)
● Verbatim-Bezeichner @ (Verbatim identifier)
C# 2.0:
● Generische Typen (Generics)
● Partielle Typen (Partial types)
● Nullbare Wertetypen (Nullable value types)
● Getter/Setter separate Zugänglichkeitsmodifikatoren (Getter/Setter separate accessibility)
● Statische Klassen (Static classes)
C# 3.0:
● Automatisch implementierte Eigenschaften (Auto-implemented properties)
● Erweiterungsmethoden (Extension methods)
● Implizit typisierte lokale Variablen (Implicitly typed local variables)
C# 4.0:
● Optionale Argumente (Optional arguments)
C# 6.0:
● Automatisch implementierte Eigenschaften (Auto-property initializers)
● Ausdruckskörpermembers (Expression bodied members)
● Null-Propagierung (Null propagator)
C# 7.0:
● Ausgangsvariablen (Out variables)
● Lokale Funktionen (Local functions)
C# 8.0:
● Nur-Lese-Instanz-Mitglieder (Readonly members)
● Statische lokale Funktionen (Static local functions)
● NULL-Sammeloperatoren (Null-coalescing operators)
C# 9.0:
● Anweisungen der obersten Ebene (Top-level statements)
Die folgenden Funktionen von C# 1.0 werden nicht unterstützt:
● Präprozessordirektiven (Preprocessor directives - #if, #region, etc)
● Attributes
● Nicht verwalteter Code (Unmanaged code: pointers, unsafe keyword, P/Invoke)
● Die aktivierten und deaktivierten Anweisungen (checked, unchecked statements)
● goto-Anweisung (goto statement)
Im Folgenden verwendete Begriffe: „Host“ bedeutet Ihre .net-Anwendung; „Skript“ bezieht sich darauf, was im Skriptcode definiert ist.
In einem Skript definierte Klassen können von anderen Skriptklassen oder von System.Object vererbt werden:
class MyScriptClass: OtherScriptClass // ok
class MyScriptClass: Object // ok
class MyScriptClass // ok, same as Object
class MyScriptClass: ArrayList // error
Eine Struktur in FastScript ist eine reguläre Klasse. FastScript fügt spezielle Methoden hinzu, um eine Struktur zu kopieren, wenn ihr Wert an eine Methode oder an eine andere Variable übergeben wird. Die Deklaration einer Variablen, die einen Strukturtyp hat, erzeugt nicht automatisch eine Instanz der Struktur:
MyStruct s; // s is null
s = new MyStruct(); // and must be initialized before use
Die im Skript definierte Klasse ist für den Host als eine Instanz von FastScript.Runtime.DataContext erkennbar.
Die folgenden Methoden können in Skriptklassen überschrieben werden:
● ToString
● Equals
● GetHashCode
Die überschriebenen Methoden werden auch vom Host verwendet.
Eine in einem Skript definierte Klasse kann Schnittstellen implementieren, die im Host definiert sind, aber dies ist nur im Skript von Bedeutung. Der Host ist nicht in der Lage, eine Instanz einer solchen Klasse als Implementierung einer Schnittstelle zu behandeln.
Nullbare Typen können nur Host-Typen verwenden.
Sie können in einem Skript nur generische Host-Typen und -Methoden verwenden. Sie können keine generischen Typen oder Methoden in einem Skript definieren.
Wenn der Hosttyp als „forwarded“ gekennzeichnet ist, muss er explizit im Host verwendet werden, damit er im Skript verwendet werden kann. Zum Beispiel:
var list = new System.ComponentModel.BindingList<int>(); // error, BindingList does not exist
Wenn Sie die folgende Codezeile zu Ihrer Anwendung hinzufügen, wird das Skript ohne Fehler kompiliert:
new System.ComponentModel.BindingList<int>();
Sie können Delegaten auf der Grundlage beliebiger (im Skript oder Host definierter) Methoden erstellen. Die Übergabe von Delegaten an den Host wird nicht unterstützt. Das Erstellen von Action<>- und Func<>-Delegaten wird ebenfalls nicht unterstützt.
Benutzerdefinierte Typkonvertierungen (im Skriptcode oder im Host) sind auf die explizit definierten Typen beschränkt. Beispiel: Wenn die Konvertierung T->int definiert ist, können Sie sie verwenden. Aber Sie können die Konvertierung T->float nicht verwenden, wenn sie nicht explizit definiert ist.
var m = new My();
int intValue = m; // ok
float floatValue = m; // Fehler
int explicitIntValue = (int)m; // ok: explicit ist nicht definiert, aber wir haben implicit
float explicitFloatValue = (float)m; // Fehler
floatValue = (int)m; // use this way
public class My
{
private object _value;
public static implicit operator int(My m) => (int)m._value;
}
Nur im Host verfügbare Typen können im Skript verwendet werden. Eine im Native AOT-Modus kompilierte Anwendung enthält möglicherweise einige der Typen (oder Typmember) nicht, die Sie in einem Skript verwenden möchten, da der Typ/das Member von der Zusammenstellung ausgeschlossen (trimmed) wurde.
Ein weiteres Problem ist die Verwendung von generischen Typen/Methoden. In Native AOT können Sie die generischen Typen verwenden, die auf dem Host verfügbar sind. Zum Beispiel verwendet der Host die Klasse List<int>, aber nicht die Klasse List<double>. Sie können erstere im Skript verwenden, aber beim Versuch, den Typ List<double> zu erstellen, wird ein Fehler ausgegeben.
Ihre Aufgabe besteht also darin, Typen (und Typmembers) in Ihrer Anwendung statisch verfügbar zu machen, damit sie in einem Skript verwendet werden können. Dies kann auf verschiedene Weise geschehen (Erstellung von Typinstanzen, Verwendung von Attributen):
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(List<>))]
public void EnsureAOTVisible()
{
var list = new List<int>();
}
Wenn ein generischer Typ statisch im Host verfügbar ist, wird seine Verwendung mit Parametern, die den Verweistyp (reference type) darstellen, unterstützt. Wenn zum Beispiel der Typ List<> verfügbar ist, können Sie die Typen List<object>, List<string>, List<ArrayList> usw. erstellen.