WebAssemblyを記述できるのはC/C++/Rustだけだと思っていないでしょうか。実はLLVMにさえなれば、他の言語でも記述できます。そのため、やろうと思えばSwiftから作ることもできるそうです。 そこで注目したいのがmono-wasmです。Monoを使ってC#で記述された内容を WebAssembly にするソフトウェアです。

mono-wasmの使い方

ごく簡単なコードです。コンソールを使うことでデバッグメッセージも流せます。

class Hello {
  static int Main(string[] args) {
    System.Console.WriteLine("hello world!");
    return 0;
  }
}

実行結果です。

Main関数が必ず実行されるようになっていますが、他の関数を呼ばせることもできます。以下はクラスにメソッドが多数定義されている例です。

using Mono.WebAssembly;
using System;

class Hello
{
    static int Factorial(int n)
    {
        if (n == 0) {
            return 1;
        }
        return n * Factorial(n - 1);
    }

    // This function is called from the browser by JavaScript.
    // Here we calculate the factorial of the given number then use the
    // Mono.WebAssembly API to retrieve the element from the DOM and set its
    // innerText property to the factorial result.
    static void FactorialInElement(int n, string element_id)
    {
        Console.WriteLine(
                "Calculating factorial of {0} into DOM element {1}",
                n, element_id);

        int f = Factorial(n);

        var elem = HtmlPage.Document.GetElementById(element_id);
        elem.InnerText = f.ToString();
    }

    static void PrintHtmlElements(HtmlElement elem, int level)
    {
        string str = "";
        for (int i = 0; i < level; i++) {
            str += "  ";
        }

        str += $"<{elem.TagName}";

        foreach (var name in elem.AttributeNames) {
            var value = elem.GetAttribute(name);
            str += $" {name}='{value}'";
        }

        str += ">";

        Console.WriteLine(str);

        var list = elem.Children;
        for (int i = 0; i < list.Count; i++) {
            var child = list[i];
            PrintHtmlElements(child, level + 1);
        }
    }

    static int Main(string[] args)
    {
        int f = Factorial(6);
        HtmlPage.Window.Alert($"Hello world! factorial(6) -> {f}");

        var bi = HtmlPage.BrowserInformation;
        Console.WriteLine($"BrowserInformation: Name {bi.Name} BrowserVersion {bi.BrowserVersion} UserAgent {bi.UserAgent} Platform {bi.Platform} CookiesEnabled {bi.CookiesEnabled} ProductName {bi.ProductName}");

        var d = HtmlPage.Document;
        Console.WriteLine($"Document Location: {d.Location}");

        PrintHtmlElements(d.DocumentElement, 0);

        var p = d.CreateElement("p");
        p.InnerText = "This text was added at runtime.";
        d.Body.AppendChild(p);

        if (args.Length > 0) FactorialInElement(0, ""); // this is a hack so that the linker does not remove the FactorialInElement() method

        return f;
    }
}

実行結果です。フラクタルが計算されています。DOMにメッセージを出力することもできます。

mono-wasmは単体の WebAssembly を出力しますが、同時にDLLと実行ファイルも読み込んで動作する仕組みです。そのためサイズは若干大きくなったり、読み込みに時間がかかりますが、将来的には改善予定です。C#で WebAssembly を記述する上で有望なソフトウェアです。

mono-wasmはC++製のオープンソース・ソフトウェア(MIT License)です。

lrz/mono-wasm