7.6 CLR/Javascript(SpiderMonkey)

Limax提供一个clrjs项目,粘合C#与Javascript,支持C#与Javascript代码之间的互操作,用于实现C#脚本模式框架下的JavaScriptHandle。这一章介绍clrjs提供的功能。


  • 7.6.2 C#与Javascript的互操作举例

    首先定义Js js = new Js();

    • Javascript操纵C#

      首先定义一个C#实验类。


      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;
      }
      

      这里应该看到,需要通过Javascript访问的对象成员必须声明为public。

      • 构造对象


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

        输出:

        Construct TestJs

        Construct TestJs with 100

        True

        在这里,类TestJs被传递进Javascript虚拟机,在类上执行new操作,也就创建了对象,通过参数个数的控制可以选择不同的构造函数进行调用。第三行把Javascript中创建的变量t0传回C#进行验证,果然是TestJs对象。


      • instanceof测试


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

        输出:

        true

        true

        在这里,t0是通过C#类TestJs构造的对象,所以instanceof操作转发给C#执行,两行代码都输出true。


        继续执行:


        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));
        

        输出:

        true

        true

        true

        true

        false

        true

        false

        true

        false

        实际上instanceof执行时,用第二个参数作为类型来测试第一个参数,所以第一条语句输出true;第二条语句,字符型进入javascript转换为串类型,所以测试为true;第三,第四条语句输出true显而易见;第五,第六条语句,javascript整数仅支持int,所以long被转换为double;第七,第八条语,既然uint为无符号类型,那么大于0x7FFFFFFF的uint只能转换为double,转换为int将变为负数,完全损失了无符号的意义;第九条语句,尽管第一个参数类型为uint, 但是javascript内部并不存在这个类型, 所以输出false,实际上,javascript的数值只有int,double两种类型,用之外的C#类型进行测试永远false


      • 方法调用


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

        输出:

        3

        如果是类的静态方法,同样可以调用。


      • 字段访问


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

        输出:

        null

        helloworld

        helloworld

        第一行代码,输出mystr中的内容,对象构造时没有初始化该字段,C#中为null,对应了Javascript中的null,第二行设置mystr的字段内容,所以第三第四行访问均正确返回了设置内容。


      • 普通属性访问


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

        输出:

        0

        10

        第一行代码输出Prop的默认初始化值0,第二行相当于读取该属性,再设置该属性,属性上加上10,所以第三行输出10。


      • 索引化属性访问


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

        输出:

        101

        Indexed Property set key = 200 value = 300

        这里可以看到索引化属性的两个方法均被正确调用。


      • 委托访问


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

        输出:

        300

        对照前面的C#代码,这里的acc实际上是一个委托,指向了add方法,所以实际上执行的是add。


      • Javascript访问C#的具体细节参见章节《脚本语言访问C#规范》


    • 复杂交互

      首先定义委托FN


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

      然后执行下面的代码


      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);
      

      输出:

      34

      事实上,这段程序在C#和Javascript之间间接递归,计算了斐波那契数列的第9项。说明了C#和Javascript进行复杂交互的可能性。


上一页 下一页