Search code examples
javascriptc#type-conversionclrclearscript

How to convert native JS array of CLR types to CLR array with Clearscript


I'm looking at converting our application from using JavaScript.NET (Noesis) to use ClearScript.

Our app contains a large number of user-created Javascript algorithms/expressions for financial calculations - I'd rather avoid having to change those if possible.

Currently with JavaScript.NET many of the user-defined algorithms follow a pattern of creating a JavaScript array containing host types and passing that as a parameter to a function on another host type. With JavaScript.NET that conversion "just works". See code below for what I'm trying to do:

using System;
using Microsoft.ClearScript;
using Microsoft.ClearScript.V8;

namespace ClearscriptPlayground
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var engine = new V8ScriptEngine())

            {
                var myClass = new MyClass();;
                engine.AddHostObject("instance", myClass);
                engine.AddHostType("MyType", HostItemFlags.DirectAccess, typeof(MyType));
                engine.Execute(
                        @"var params = [new MyType('bye', 10), 
                                        new MyType('hello', 10)];

                          instance.SomethingElse(params)");

                Console.ReadLine();
            }
        }
    }

    public class MyClass
    {
//        public void SomethingElse(ITypedArray<MyType> foo)
//        {
//            // Doesn't work.
//        }

//        public void SomethingElse(MyType[] foo)
//        {
//            // Doesn't work.
//        }

//        public void SomethingElse(dynamic foo)
//        {
//            var mapped = foo as ITypedArray<MyType>; // Doesn't work
//            var mapped = foo as MyType[]; // Doesn't work either   
//        }

        public void SomethingElse(ScriptObject foo)
        {
            // Works, but how best to convert to MyType[] or similar?
        }
    }

    public struct MyType
    {
        public string Foo;
        public int Bar;

        public MyType(string foo, int bar)
        {
            Foo = foo;
            Bar = bar;
        }
    }
}

NB: I know that I can create a host array using params = host.newArr(MyType, 2); and that will work - but that would mean modifying all the user-maintained JavaScript which I'd really rather avoid.


Solution

  • You can use the JavaScript array directly via dynamic:

    public void SomethingElse(dynamic foo)
    {
        var length = foo.length;
        for (var i = 0; i < length; ++i)
        {
            var my = (MyType)foo[i];
            Console.WriteLine("{0} {1}", my.Foo, my.Bar);
        }
    }