Serialization
Most simple types, such as numbers, booleans, strings, arrays (lists) and promises (tasks) of them are marshalled in-memory when crossing the C# <-> JavaScript boundary. Below are some of the natively-supported types (refer to .NET docs for the full list):
| C# | JavaScript | Task of | Array of |
|---|---|---|---|
| bool | boolean | ✔️ | ❌ |
| byte | number | ✔️ | ✔️ |
| char | string | ✔️ | ❌ |
| string | string | ✔️ | ✔️ |
| int | number | ✔️ | ✔️ |
| long | BigInt | ✔️ | ❌ |
| float | Number | ✔️ | ❌ |
| DateTime | Date | ✔️ | ❌ |
When a value of non-natively supported type is specified in an interop API, Bootsharp will de-/serialize it using a custom efficient binary serialization format. The whole process is encapsulated under the hood on both the C# and JavaScript sides, so you don't have to manually author generator hints or specify [MarshallAs] attributes for each value:
public record User (long Id, string Name, DateTime Registered);
[Export]
public static void AddUser (User user) { }
[Export]
public static event Action<User>? OnUserModified;— Bootsharp will automatically emit C# and JavaScript code required to de-/serialize User record on both ends, so that you can consume the APIs as if they were initially authored in JavaScript:
import { Program } from "bootsharp";
Program.addUser({ id: 17, name: "Carl", registered: Date.now() });
Program.onUserModified.subscribe(handleUserModified);
function handleUserModified(user: Program.User) { }NOTE
Only types with immutable semantics (structs, records, and read-only collections) are subject to serialization—other types are considered mutable and are passed by reference as interop instances.
Enums Serialization
Enums are marshalled as numbers for better performance, while additional name <-> index mappings are emitted on the JavaScript side for convenience.
public enum Options { Foo, Bar }
[Export]
public static Options GetOption () => Options.Bar;— while "GetOptions" return value will be passed to JavaScript as an integer index, Bootsharp will map enum indexes to string values (and vice-versa) in the emitted code, so that following will work as expected:
import { Program } from "bootsharp";
const option = Program.getOption();
console.log(option === Program.Options.Foo); // false
console.log(option === Program.Options.Bar); // true
console.log(Program.Options[Program.Options.Foo]); // "Foo"
console.log(Program.Options[1]); // "Bar"Dictionary Serialization
Bootsharp marshals C# dictionaries as ES6 Map:
[Export]
public static Dictionary<string, bool> GetMap () =>
new () { ["foo"] = true, ["bar"] = false };— the dictionary can be accessed with standard Map APIs:
import { Program } from "bootsharp";
const map = Program.getMap();
console.log(map.get("foo")); // true
console.log(map.get("bar")); // falseCollection Interfaces
It's common to use various collection interfaces, such as IReadOnlyList or IReadOnlyDictionary when authoring C# APIs. Bootsharp will accept any kind of array or dictionary compatible interface in the interop APIs and marshal them as plain arrays and maps by default:
[Export]
public static IReadOnlyDictionary<string, float> Map (
IReadOnlyList<string> a, IReadOnlyCollection<float> b) { }import { Program } from "bootsharp";
const map = Program.map(["foo", "bar"], [0, 7]);
console.log(map.get("bar")); // 7