7.6 CLR/Javascript(SpiderMonkey)

The Limax provides a clrjs project, which combines the C# and Javascript, supports the code interoperability between the C# and Javascript, and implements the JavaScriptHandle in the framework of the C# script model. This charpter introduces the functions provided by the clrjs.


  • 7.6.3 Type mapping

    It is not compatible at all in the type of system between C# and Javascript two languages. So type mapping can not be described in a definite form. It is discussed in three rules.

    • Rule #1: C# transfers to Javascript (C# transfers to Javascript via eval; when Javascript accesses C#, the return object be constructed, return value of the method, return value of the delegation, access fields, and access property)

      In this condition, the type information of C# could be clearly obtained.

      • null, is interpretted as the null of the Javascript

      • DBNull.Value, is interpretted as the undefined of the javascript

      • bool and the boxing type Boolean, are interpretted as the boolean of the javascript

      • When C# passes to the Javascript, byte, sbyte, short, ushort, int and boxing type Byte, SByte, Int16, UInt16 and Int32 are interpretted as the int of the Javascript.

      • float, double, decimal and boxing type Single, Double, Decimal are interpretted as the double of the Javascript.

      • uint and the boxing type UInt32, if the value is less than 0x80000000, they are interpretted as the int of the javascript, or as the double of the javascript.

      • char, string and the boxing type Char, String are interpretted as the string of the Javasript. It should be noted that the character string has changed to the javascript string after it is transferred to the javascript, and can not be accessed through calling the character string method of C#. If executing js.eval("print(<0>.Length)", "abc"); , the undefined will be outputted. It should be changed to js.eval("print(<0>.length)", "abc"); to get the correct result 3. The grammar is a little weird and should be careful.

      • The C# object except for JsObject, JsArray and JsFunction, create a special object in javascript to associate with it, reference to this C# object via SetPrivate to prevent to be GC in the C# virtual machine. Particularly, if the type is delegation type, the Invoke method of the delegation object is obtained as the object that is actually associated to it, so the delegation object can be correctly called.

      • JsObject, JsArray and JsFunction are the type returned to the C# previously, and get the previous associated Javascript object at this time.


    • Rule #2:Javascript return value to C# (the return of eval)

      In this condition, only return based on the currently known information of Javascript. After C# gets this return value, it should strictly check the type before using, or it might cause the type conversion exeception, System.InvalidCastException.

      • null, returns null.

      • undefined, returns DBNull.Value.

      • Boolean, returns Boolean.

      • string, returns String.

      • int, returns Int32.

      • double, returns Double.

      • Reference to the special javascript object of the C# object via SetPrivate, return the referenced C# object.

      • The other javascript object, creates a JsObject object to reference to it, to prevent to be GC in the javascript virtual machine. This JsObject is returned.

      • The Javascript objects except for array and function use JsObject to return. The JsObject implements the IDictionary interface not IDictionary specification. For example, the IDictionary throws exception when repeating Add, and Javascript executes replacement when repeating Add; Remove property on JsObject has the same effect as Add a DBNull.Value on property.

      • The Javascript arrary use JsArray to return. The JsArray inherits from the JsObject, implements the IList interface, and access the corresponding javascript array's member through this interface. The JsArray accesses according to the Javascript specification, not IList specification. The JsAarry does not generate System.ArgumentOutOfRangeException exception, which means no array out of range issue. The IList interface implemented by JsArray and ICollection interface inherited from the JsObject object, have the problem that the property and method have the same name. Because the new rule is used to override, using the JsArray way and JsObject way might cause different result, and the previous sample could be reviewed.

      • Javascript function uses JsFunction delegation to return. This delegation encapsulates an object inherited from JsObject as the Javascript function.

      • It should be noted that the conversion (int)js.eval("3.14"); certainly causes System.InvalidCastException. The reason is that the returned javascript value is , and the returned type is System.Double. This kind of boxing type can not be directly converted to int as the primitive double type. The correct usage is (int)(double)js.eval("3.14");. Once there is type conversion exception, it could call the getType() method on the returned object to check the real type and determine whether it matches the requirements in order to correctly convert.

      • The Javascript specification is continually updated. A number of specific access control attributes are specified for the object properties, such as the property set as readonly can not be correctly modified. For example, executing code js.eval("print=100; print('readonly')"); will output readonly. This kind of case should be careful. However, in general, not the objects, methods and types built in system have no this issue.


    • Rule #3:Javascipt passes to C# (construct parameters, method calling parameters, delegation calling parameters, fields setting, properties setting)

      First convert to C# object according to rule #2, then convert in C# accroding to the expected parameter type. Refer to the charpter <The specification that the script language accesses C#> for the details.


  • 7.6.4 Exception specification

    • C# and Javascipt support the exception framework. These two languages could catch the exception.

    • When C# calles Javascript, if the Javascript throws exception and does not catch, the exception is thrown to the C#.

    • When Javascript calles C#, if the C# throws exception and does not catch, the exception is thrown to the Javascript.

    • C# and Javascript could be nested each other. Without catching, the exception could be thrown to the outmost nested layer.

    • Every time the exception enters C#, the limax.script.Js.ScriptException is used to encapsulated.

    • ScriptException treates the Javascript exception string as the exception message, and the C# exception as the internal exception to encapsulate.

    • The Javascript exception string is concated with the file location information, exception message and StackTrace. For Javascript, the thrown Error includes the location information and StackTrace.

    • In Javascript, calling toString on catched exception object, the complete information could be obtained, including the exception information from C#.


  • 7.6.5 Thread safety

    • The SpiderMonkey library does not allow the virtual machine to run accross threads. Any operation executing on the javascript operating object, including eval, and the operation on the JsObject, JsArray and JsFunction returned by eval, must be executed in the thread creating javascript operating object, or throw the exception limax.script.Js.ThreadContextException.


  • 7.6.6 Matters need attention

    • 1. The generic object of C# can not be transferred to Javascript virtual mathine, or throws exception. The reason is that System::Runtime::InteropServices::Marshal::GetNativeVariantForObject and System::Runtime::InteropServices::Marshal::GetObjectForNativeVariant these two key methods' generic version is provided since .NET4.5.1. For compatibility with older .NET versions, this project uses .NET4.0 to develop (.NET3.5 also could be used).

    • 2. Could create multiple Javascript operating objects. The JsObject, JsArray and JsFunction obtained from one Javascript object can not be transferred to another Javascript operating object, which is obvious. There is no limitation for the other C# object to transfer multiple Javascript operating objects. If there is data exchange requirment for the multiple Javascript operating objects, it could be realized through JSON and the Javascript itself provides the complete support with the limitation that there is no ring in the objects.


Prev Next