microsoft / node-api-dotnet

Advanced interoperability between .NET and JavaScript in the same process.
MIT License
426 stars 49 forks source link

Support marshalling C# `dynamic` values #307

Open Lysom opened 1 week ago

Lysom commented 1 week ago

node-api-dotnet version: 0.7.* dotnet sdk: .net 6.0 nodejs version: 18.18.1 I tried to excute C# dll methods which is task method , the method parameter and return value's type is dynamic. I got empty object when i used async/await in nodejs, could someone help me about this problem, thks.

jasongin commented 1 week ago

Can you share some relevant snippets of the code?

the method parameter and return value's type is dynamic.

Do you mean literally C# dynamic type? If so, that is not currently supported. I think it could be supported, but use of dynamic is so uncommon that it hasn't been a priority.

Lysom commented 1 week ago

Can you share some relevant snippets of the code?

the method parameter and return value's type is dynamic.

Do you mean literally C# dynamic type? If so, that is not currently supported. I think it could be supported, but use of dynamic is so uncommon that it hasn't been a priority.

Thanks for your reply. Yes, I am indeed referring to the dynamic type in C#. My project previously utilized electron-edge-js, which supported parameters and return values of type dynamic. However, electron-edge-js has encountered numerous issues, prompting me to attempt a restructuring using node-api-dotnet.

jasongin commented 1 week ago

The main reason dynamic isn't currently supported is that this project uses a different approach to marshalling values between .NET and JS compared to edge-js. Since edge-js relies entirely on runtime reflection, it can handle dynamic (or object) just as well as any other type, since a value's type is always inspected at runtime. On the other hand node-api-dotnet relies on code generation, which requires the parameter or return value to have a specific declared type. (Either compile-time or runtime code-generation can be used, depending on the scenario.) The code generation approach results in much better performance, since reflection is relatively slow. And Native AOT compatibility is another benefit of code generation.

To support dynamic and object value types, we could check the value's actual type at runtime, and then do the necessary runtime code-generation (if the marshalling code was not already generated for the reflected type). It wouldn't work with AOT though.

jasongin commented 1 week ago

I updated the title of this issue to make it a feature request for dynamic support.

Meanwhile, could you consider alternatives to dynamic typing in C#? Options are:

Lysom commented 1 week ago

I updated the title of this issue to make it a feature request for dynamic support.

Meanwhile, could you consider alternatives to dynamic typing in C#? Options are:

  • Declare a C# struct or interface for the shape of your JS object, and tag it with [JSExport].
  • Use JSValue, which provides access to arbitrary JS properties.

Thanks for your help, I'll try it.