7.7 The specification that the scripting language accesses C#

The Limax provides limax.util.ReflectionCache class to give the possiblely complete support for script language to access C# object. Currently it is used by CLR/Lua and CLR/Javascript.


  • 7.7.1 Programming interface

    Constructor:

    • ReflectionCache(ToStringCast toString)

      toString, is defined as the delegation delegate object ToStringCast(object obj); to instruct the script system to execute corresponding ToString operation. Some script system objects might be the packing with the specific implementation. So this method provides the chance to unpack and then ToString.


    Method:

    • object GetValue(object obj, object name)

      obj, accessed C# object.

      name, accessed C# object's member

      This method returns the value of the C# object member, and the member could be field, property and method. If the method is returned, the Invokable interface is used to encapsulate so that it is convenient to called by the scripting language in the next step. The type of name is object not string. The reason is that the scripting language has two ways to access the object, obj.member and obj[member]. In the first way, the member must be string type, but the second way is not. The second way is similar with the indexed property access way of C#, so it could be used to support the access to the single parameter indexed property. At this time, the definition of the name is not field, property, or method, but indexed parameter.


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

      obj, accessed C# object

      name, accessed C# object's member

      value, the value expected to set to the member

      This method sets an value for the C# object member. The member could be field and property. If the name specifies a method member, the execution of SetValue has no any effect. Similar with GetValue, this method is also used by indexed property.


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

      obj, type object

      parameters, construct funtion parameter

      This method constructs and returns an instance of the type object obj. The obj must be the derived class of the Type, or throws System.InvalidCastException when calling.


    Interface:

    • interface Invokable

      This interface is used to encapsulate the object method so that it is convenient to be called by scripting language. It includes two members:


      object Invoke(object[] parameters);
      

      Use parameter parameters to call the encapsulated object method.


      object GetTarget();
      

      Refer the section "Correctly handle the delegation".


    System.DBNull.Value:

    The non-existed value is represented with DBNull.Value in C#. There is difference in the understanding about the non-existed value for script languages, for example, the Javascript uses undefined to indicate that the value does not exist. There is ambiguity in Lua, sometimes non-exist means nothing at all, and placeholder is also not acceptable; sometimes it means nil, and an experimental description could be used in the Lua console program:

    Define function:


    function undefined() end
    

    Execute:


    print(undefined())
    

    The output is blank. From the description of the statement, print has one parameter, which is the return value of the undefined() function. Actually, there is no return value at all, so the print finds that the parameter number is 0 when executing and the output is blank. To prove this conclusion, use CLR/Lua to do an experiment:


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

    output:

    empty

    Back to Lua console program and continue execute:


    value = undefined()
    print(value)
    

    The output is nil.

    This can be interpreted as that the assignment statement must be executed but no value, so nil is used to replace. For this interpretation, it is necessary to raise a question: why not explain that the assignment statement is not executed. After all, the value has not been initiated. So continue the experiment:

    Then execute:


    value = 100
    print(value)
    

    Output:

    100

    Then execute:


    value = undefined()
    print(value)
    

    Output:

    nil

    The above experiment proves that the ambiguity is caused becuase Lua does not support the non-existed value. The implementation of CLR/Lua is fully compatible with Lua's feature, and these issues also exist and must be careful.


    Access scope:

    • The object's fields, properties and methods which need to be provided to scripting language to access are restricted as public.

    • The fields, properties and methods of the object itself can be accessed, but does not include the inherited base class's members.

    • The above two restrictions are easy to break, however, it is not recommended from programming specification. For the first entry, it is not reasonable to access the members which C# code itself is restricted to access through the scripting language. For the second entry, as much as possible to use interface and less use class inheritance is a better programming way. There is no reason to guide the bad hibits.


  • 7.7.2 Construct object

    Call Construct method to construct the object. The detailed execution process is same as the method calling and will be introduced later.


  • 7.7.3 Field access

    • Read fields

      When GetValue, if the parameter of name is string type and the value matches the current object's filed name, execute the field reading.


    • Write fields

      When SetValue, if the parameter of name is string type and the value matches the current object's field name, use value to write field. The type of value provided by the scripting language might not match the actual type of the field, so the type conversion must be executed firstly. There is possbile to throw exception when type conversion fails.


Prev Next