7.7 脚本语言访问C#规范

Limax提供limax.util.ReflectionCache类,为脚本语言访问C#对象提供尽量完整的支持。当前由CLR/Lua,CLR/Javascript使用。


  • 7.7.1 编程接口

    构造函数:

    • ReflectionCache(ToStringCast toString)

      toString, 定义为委托delegate object ToStringCast(object obj);指令脚本系统执行相应的ToString操作, 某些脚本系统对象, 可能只是具体实现的包装, 该方法提供了解包装再ToString的机会。


    成员函数:

    • object GetValue(object obj, object name)

      obj,被访问的C#对象

      name,被访问的C#对象的成员

      该方法返回了C#对象成员的值,成员可以是字段,属性,方法。如果返回的是方法,使用Invokable接口包装,便于下一步被脚本语言调用。name的类型为object,而不是string,这是因为脚本语言访问对象一般两种形式obj.member,obj[member],第一种形式,member必然是string类型,第二种形式则不然,第二种形式与C#的索引化属性访问方式类似,所以可以被利用来支持单参数索引属性的访问,这时name的含义不再是字段,属性,或者方法,而是索引参数。


    • void SetValue(object obj, object name, object value)

      obj,被访问的C#对象

      name,被访问的C#对象的成员

      value,期望给成员设置的值

      该方法为C#对象成员设置一个值,成员可以是字段,属性,如果name指定了方法成员,SetValue的执行没有任何效果。类似GetValue,该方法同样被索引化属性利用。


    • object Construct(object obj, object[] parameters)

      obj,类型对象

      parameters,构造函数参数

      该方法构造并返回类型对象obj的一个实例,obj必须是Type派生类,否则调用抛出System.InvalidCastException。


    接口成员:

    • interface Invokable

      该接口用于包装对象方法,便于被脚本语言调用,包含两个成员:


      object Invoke(object[] parameters);
      

      使用参数parameters调用包装的对象方法


      object GetTarget();
      

      见正确处理委托一节。


    System.DBNull.Value:

    不存在的值在C#中用DBNull.Value表示。脚本语言在不存在的值的理解上存在差异,比如Javascript用undefined表示值不存在;而Lua中存在二义性,有时候不存在就是完全没有,占位都不行;有时候又认定为nil,可以在Lua控制台程序中做一个实验说明:

    定义函数:


    function undefined() end
    

    执行:


    print(undefined())
    

    输出是空白,从语句的描述来看,print有一个参数,那就是undefined()函数的返回值, 实际上, 返回值根本没有, 所以print执行的时候发现参数数量为0, 输出空白。要证明这个结论, 可以用CLR/Lua做一个实验:


    Action a = () => Console.WriteLine("empty");
    lua.eval("function undefined() end\n<0>(undefined())", a);
    

    输出

    empty

    回到Lua控制台程序,继续执行:


    value = undefined()
    print(value)
    

    输出竟然是nil !!!

    可以解释为,赋值语句必需执行,但是没有值,只好用nil代替。对于这种解释,又必需提出一个问题,为什么不可以解释成赋值根本没有执行,毕竟value还没有初始化过?所以还得继续实验:

    再执行:


    value = 100
    print(value)
    

    输出

    100

    再执行:


    value = undefined()
    print(value)
    

    输出:

    nil

    上面的实验见证了Lua不支持不存在的值导致的二义性。CLR/Lua在实现上保证和Lua的特性完全兼容,这些问题同样存在,必须小心。


    访问范围:

    • 需要提供给脚本语言访问的对象字段,属性,方法,限定为public

    • 对象本身的字段,属性,方法可以被访问,不包括继承的基类成员。

    • 以上两点限制很容易突破,不过,从编程规范化的角度看,不建议。对于第一条,C#本身代码都被限制访问的成员,通过脚本语言反而能访问完全不存在合理性;对于第二条,尽量多使用接口,少使用类继承,是更好的编程方式,没有理由往不好的习惯上引导。


  • 7.7.2 构造对象

    调用Construct方法,即可构造对象,具体执行流程与方法调用相同,之后介绍。


  • 7.7.3 字段访问

    • 读字段

      GetValue时,name参数为string类型,值与当前对象的字段名匹配,执行字段读取。


    • 写字段

      SetValue时,name参数为string类型,值与当前对象的字段名匹配,用value写字段,脚本语言提供的value类型可能与字段实际类型不匹配,所以必须先执行类型转换,类型转换有失败抛出异常的可能。


上一页 下一页