microsoft/node-api-dotnet

InvalidOperationException On generic type

Closed this issue · 5 comments

[JSExport]
public class ProxyArray<T> : ProxyTypeBase, IList<T>, ICollection<T>, IEnumerable<T>
{
    private List<T> _raw;

    public ProxyArray()
    {
        _raw = new List<T>();
    }
}

//Get Compile Error :

CSC : error NAPI1001: InvalidOperationException : Unknown generic type parameter T in type jj.Jex.Runtime.ProxyTypes.ProxyArray`1 在 Microsoft.JavaScript.NodeApi.Generator.SymbolExtensions.AsType(ITypeSymbol typeSymbol, Type[] genericTypeParameters, Boolean buildType) 在 System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext() 在 System.Linq.Buffer`1..ctor(IEnumerable`1 source) 在 System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source) 在 Microsoft.JavaScript.NodeApi.Generator.SymbolExtensions.AsType(ITypeSymbol typeSymbol, Type[] genericTypeParameters, Boolean buildType) 在 Microsoft.JavaScript.NodeApi.Generator.SymbolExtensions.AsConstructorInfo(IMethodSymbol methodSymbol) 在 System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() 在 System.Linq.Buffer`1..ctor(IEnumerable`1 source) 在 System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source) 在 Microsoft.JavaScript.NodeApi.Generator.ModuleGenerator.ExportType(SourceBuilder& s, ITypeSymbol type, String exportName)

So Template Type is not supported now ? Or How I can get those type exported?

Exporting a generic type to JavaScript using static binding ([JSExport]) is not supported. There is an issue (#298) about reporting a better error message in that case. However it is possible to dynamically load and use any kind of generic types. For more details see https://microsoft.github.io/node-api-dotnet/reference/generics.html

What is your goal with the ProxyArray<T> type? Are you aware that generic collection interfaces like IList<> are already marshalled by reference (proxy)? So you can pass an IList<> or IDictionary<,> from .NET to JS, and have both .NET and JS code reading and writing items in the same collection. https://microsoft.github.io/node-api-dotnet/reference/arrays-collections.html#generic-interfaces

I want use property set method to trace the item change event.

OK, to accomplish that you can still implement a ProxyArray<T> class while exporting it as only a IList<T>. Something like this:

[JSExport]
public static class ProxyArrayFactory
{
    public static IList<int> CreateProxyArrayOfInt() => new ProxyArray<int>();
    public static IList<string> CreateProxyArrayOfString() => new ProxyArray<string>();
}

// Not exported
internal class ProxyArray<T> : IList<T>
{
    private List<T> _inner = new List<T>();

    public T this[int index]
    {
        get => _inner[index];
        set
        {
            Console.WriteLine($"Setting [{index}] = {value}.");
            _inner[index] = value;
        }
    }
}

In JavaScript the proxies will look and act like JS arrays, but they proxy all calls to .NET via IList<T>.

const proxyArray = ProxyArrayFactory.createProxyArrayOfInt();
assert(Array.isArray(proxyArray));

I'm closing this because the question was answered and there's another issue tracking a better error message. If you're still having trouble, feel free to reopen this, or open a new issue.

This is also related to / duplicate of #289