Question about passing generic List.

Sep 23, 2015 at 8:00 PM
I am trying to convert an C# application that used VSA JScript engine to use ClearScript with V8 engine. I have a question about how ClearScript handles generic list. I have the follow sample code:
    public class Item { public int Value; }
    public IList<Item> MyList = new List<Item>() { new Item(), new Item(), new Item() };

    void ClearScriptTest(object sender, EventArgs e) {
        using (var engine = new V8ScriptEngine()) {
            engine.AddHostObject("Me", this);
            engine.Execute("Me.MyList[0].Value = 123;");
            MessageBox.Show(MyList[0].Value.ToString());
        }
    }
When I run this code, an exception "TypeError: Cannot set property 'Value' of undefined"
will be thrown. However when I change the declaration type of MyList from IList<int> to List<int>, then the code works. It looks like that engine.Execute() uses the static declaration type instead of the actual type of the object Me.MyList. Is this a defect ? The old VSA JScript engine behaviors differently. Is there a way to configure ClearScript to fix this problem?
Coordinator
Sep 24, 2015 at 1:27 PM
Edited Sep 24, 2015 at 1:28 PM
Hello!

Here's what's going on. In your script code, the expression Me.MyList is of the managed type IList<Item>. This type has an indexer that is actually an indexed property named "Item". ClearScript supports indexed properties, but it requires the following syntax:
// JavaScript
var value = Me.MyList.Item.get(index); // or Me.MyList.Item(index)
Me.MyList.Item.set(index, value);
When you change the type to List<Item>, you enable ClearScript's special treatment of objects that implement IList. This feature supports array-like access from script code:
// JavaScript
var value = Me.MyList[index];
Me.MyList[index] = value;
Note that IList<T> is not derived from IList and therefore doesn't trigger this feature.

It looks like that engine.Execute() uses the static declaration type instead of the actual type of the object Me.MyList. Is this a defect ?

No, this is by design. ClearScript's goal is to provide C#-like access to .NET types. .NET supports things like generic and overloaded methods, and C# method binding relies on static analysis of the method arguments. Script languages don't support static typing, so ClearScript simulates it with a feature called type restriction, which allows C#-like method binding to take place at runtime.

Is there a way to configure ClearScript to fix this problem?

You can use ClearScript's ScriptMemberAttribute to expose the runtime type of a given member:
[ScriptMember(ScriptMemberFlags.ExposeRuntimeType)]
public IList<Item> MyList = new List<Item> { new Item(), new Item(), new Item() };
You can also use the engine's DisableTypeRestriction property to turn off type restriction globally, but doing so can break some method invocation scenarios.

Good luck!
Sep 24, 2015 at 5:12 PM
Thanks you so much for the quick replay. It is exactly what I was looking for!

Since we use JavaScript interface for less trained end-users, we really
prefer the relaxed and forgiving behavior. I hope the flag DisableTypeRestriction
won't be deprecated in the future.

It looks like that the C# class String is treated specially. Even with DisableTypeRestriction enabled,
methods of String class, like EndsWith(), are not exposed to script interface. Is there a general way
to enable such run-time type methods?

Another similar issue I encountered is that when a C# method expects an argument,
but when it is called in a script without argument, the script execution will fail with an exception.
The old VSA JScript engine will call the method with default values (like null or 0). Is there a general
property in ClearScript that enable such auto-argument-filling feature?
Coordinator
Sep 24, 2015 at 8:51 PM
Hi again,

It looks like that the C# class String is treated specially. Even with DisableTypeRestriction enabled, methods of String class, like EndsWith(), are not exposed to script interface. Is there a general way to enable such run-time type methods?

Strings and numbers are just about the only objects for which ClearScript performs automatic data conversion. For more information, see here.

Another similar issue I encountered is that when a C# method expects an argument, but when it is called in a script without argument, the script execution will fail with an exception. The old VSA JScript engine will call the method with default values (like null or 0). Is there a general property in ClearScript that enable such auto-argument-filling feature?

No, ClearScript does not support automatic argument filling, as its method binding algorithm is based on an analysis of the argument types. However, it does support default arguments, so if you're designing the API being exposed to the script engine, you can specify default arguments as necessary to provide similar flexibility.

Cheers!