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.2 Interoperability example between C# and Javascript

    First, define Js js = new Js();

    • Javascript controls C#

      First, define a C# experimental class.


      public class TestJs
      {
      	public TestJs() { Console.WriteLine("Construct TestJs"); acc = add; }
      	public TestJs(int x) { Console.WriteLine("Construct TestJs with " + x); acc = add; }
      	public int add(int a, int b) { return a + b; }
      	public string mystr;
      	public int Prop { get; set; }
      	public int this[int x]
      	{
      		get { return x + 1; }
      		set { Console.WriteLine("Indexed Property set key = " + x + " value = " + value); }
      	}
      	public delegate int ACC(int a, int b);
      	public ACC acc;
      }
      

      Seen from here that the member of object accessed by Javascript must be declared as public.

      • Construct object


        js.eval("var t0 = new<0>()", typeof(TestJs));
        js.eval("var t1 = new<0>(100)", typeof(TestJs));
        Console.WriteLine(js.eval("t0") is TestJs);
        

        Output:

        Construct TestJs

        Construct TestJs with 100

        True

        Here the class TestJs is transferred into Javascript vm, executes the new operation on the class to create the object, and selects the different construct function to call through controlling the parameter number. The third line transferres the variable t0 created in the Javascript to the C# to verify and it is TestJs object.


      • instanceof test


        js.eval("print(t0 instanceof <0>)", typeof(object));
        js.eval("print(t0 instanceof <0>)", typeof(TestJs));
        

        Output:

        true

        true

        Here the t0 is the object constructed through C#' TestJs class. So the instanceof operation is transferred to C# to execute. These two lines output true.


        Continue execute:


        js.eval("print('abc' instanceof <0>)", typeof(string));
        js.eval("print(<0> instanceof <1>)", 'a', typeof(string));
        js.eval("print(100 instanceof <0>)", typeof(int));
        js.eval("print(<0> instanceof <1>)", 100, typeof(int));
        js.eval("print(<0> instanceof <1>)", 100L, typeof(int));
        js.eval("print(<0> instanceof <1>)", 100L, typeof(double));
        js.eval("print(<0> instanceof <1>)", UInt32.MaxValue, typeof(uint));
        js.eval("print(<0> instanceof <1>)", UInt32.MaxValue, typeof(double));
        js.eval("print(<0> instanceof <1>)", (uint)10, typeof(uint));
        

        Output:

        true

        true

        true

        true

        false

        true

        false

        true

        false

        Actually, when instanceof executes, the second parameter is used as the type to test the first parameter, so the first statement outputs true; for the second statment, the character type is converted to the string type in javascript, so the test is true; it is clear that the third and forth statments output true; for the fifth and sixth statments, the javascript integer only supports int, so long is converted to double; for the seventh and eighth statements, since unit is an unsigned type, the unit greater than 0x7FFFFFFF is converted to double because it will become negative when converted to int and completely lose the meaning of unsigned; for the ninth statement, even though the first paramenter is uint, there is no this type in the javascript and outputs false. Actually, there are only int and double types in the javascrip's values, and test with the other than C# type is always false.


      • Call method


        js.eval("print (t0.add(1,2))");
        

        Output:

        3

        If it is the class's static method, it also could be called.


      • Access field


        js.eval("print(t0.mystr)");
        js.eval("t0.mystr='hello world'");
        Console.WriteLine(js.eval("t0.mystr"));
        Console.WriteLine(((TestJs)js.eval("t0")).mystr);
        

        Output:

        null

        helloworld

        helloworld

        The first line of the code, outputs the content of mystr. This filed does not be initiated when constructing object, and it is null in C# which corresponds to the null of Javascript. The second line sets the content of mystr field, so the third and forth line correctly return the set content when accessing.


      • Access normal property


        js.eval("print(t0.Prop)");
        js.eval("t0.Prop = t0.Prop + 10");
        Console.WriteLine(js.eval("t0.Prop"));
        

        Output:

        0

        10

        The first line of the code outputs the default initiation value 0 of Prop. The second line equals to read this property, then set this property with 10 added to it. So the third line outputs 10.


      • Access indexed property


        js.eval("print(t0[100])");
        js.eval("t0[200] = 300");
        

        Output:

        101

        Indexed Property set key = 200 value = 300

        Seen from here that the two methods of the indexed property are correctly called.


      • Access delegation


        js.eval("print(t0.acc(100,200))");
        

        Output:

        300

        Compared with the previous C# code, the acc here is actual a delegation which points to add method. So actually the add is executed.


      • Refer to the charpter <The specification that the script language assesses C#> for the details about Javascript accessing C#


    • Complex interaction

      First, define the delegation FN.


      public delegate int FN(object f, int a);
      

      Then, execute the following code.


      FN fn = (object f, int a) => (int)js.eval("<1><2?<1>:<0>(<0>,<1>-1)+<0>(<0>,<1>-2);", f, a);
      js.eval("print(<0>(<0>,<1>))", fn, 9);
      

      Output:

      34

      Actually, this program is indirectly recursive between C# and Javascript, calculating the ninth term of the Fibonacci sequence. It presents the possibility of the complex interaction between C# and Javascript.


Prev Next