virtualx-engine/modules/mono/editor
Ignacio Roldán Etcheverry 282bd37e5c C#: Remove need for reflection to invoking callable delegates
We aim to make the C# API reflection-free, mainly for concerns about
performance, and to be able to target NativeAOT in refletion-free mode,
which reduces the binary size.

One of the main usages of reflection still left was the dynamic
invokation of callable delegates, and for some time I wasn't sure
I would find an alternative solution that I'd be happy with.

The new solution uses trampoline functions to invoke the delegates:

```
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
{
    if (args.Count != 1)
        throw new ArgumentException($"Callable expected 1 arguments but received {args.Count}.");

    string res = ((Func<int, string>)delegateObj)(
        VariantConversionCallbacks.GetToManagedCallback<int>()(args[0])
    );

    ret = VariantConversionCallbacks.GetToVariantCallback<string>()(res);
}

Callable.CreateWithUnsafeTrampoline((int num) => "Foo" + num, &Trampoline);
```

Of course, this is too much boilerplate for user code. To improve this,
the `Callable.From` methods were added. These are overloads that take
`Action` and `Func` delegates, which covers the most common use cases:
lambdas and method groups:

```
// Lambda
Callable.From((int num) => "Foo" + num);

// Method group
string AppendNum(int num) => "Foo" + num;
Callable.From(AppendNum);
```

Unfortunately, due to limitations in the C# language, implicit
conversions from delegates to `Callable` are not supported.

`Callable.From` does not support custom delegates. These should be
uncommon, but the Godot C# API actually uses them for event signals.
As such, the bindings generator was updated to generate trampoline
functions for event signals. It was also optimized to use `Action`
instead of a custom delegate for parameterless signals, which removes
the need for the trampoline functions for those signals.

The change to reflection-free invokation removes one of the last needs
for `ConvertVariantToManagedObjectOfType`. The only remaining usage is
from calling script constructors with parameters from the engine
(`CreateManagedForGodotObjectScriptInstance`). Once that one is made
reflection-free, `ConvertVariantToManagedObjectOfType` can be removed.
2022-10-30 01:24:15 +02:00
..
Godot.NET.Sdk C#: Remove need for reflection to invoking callable delegates 2022-10-30 01:24:15 +02:00
GodotTools [.NET Export] Improve .NET export process. 2022-10-07 13:33:06 +03:00
script_templates C#: Assume 64-bit types when type has no meta 2022-09-01 10:29:52 +02:00
bindings_generator.cpp C#: Remove need for reflection to invoking callable delegates 2022-10-30 01:24:15 +02:00
bindings_generator.h C#: Assume 64-bit types when type has no meta 2022-09-01 10:29:52 +02:00
code_completion.cpp Rename String plus_file to path_join 2022-08-29 19:38:13 -05:00
code_completion.h Update copyright statements to 2022 2022-01-03 21:27:34 +01:00
editor_internal_calls.cpp Port remaining connections to callable_mp 2022-09-18 13:08:54 +02:00
editor_internal_calls.h C#: Replace P/Invoke with delegate pointers 2022-08-22 03:36:52 +02:00
hostfxr_resolver.cpp Fix MacOS compiler flags in .NET module 2022-09-08 23:29:01 +02:00
hostfxr_resolver.h C#: Replace libnethost dependency to find hostfxr 2022-09-07 16:36:36 +02:00
semver.cpp C#: Replace libnethost dependency to find hostfxr 2022-09-07 16:36:36 +02:00
semver.h C#: Replace libnethost dependency to find hostfxr 2022-09-07 16:36:36 +02:00