Base script object

Feb 28, 2013 at 3:54 AM
Hi,

I noticed that .Evaluate() returns a simple "object" type. Is there actually a type I can cast this to? (i.e. is there a common ClearScript base object type?)
Coordinator
Feb 28, 2013 at 3:40 PM
Edited Aug 3, 2013 at 3:34 AM
Hello jamesnw!

Because ClearScript is designed to integrate as seamlessly as possible with .NET, System.Object is the common base class. In general, script code can return one of the following categories of objects:
  • Strings: System.String.
  • Boolean values: System.Boolean
  • Numbers: System.Int32 or System.Double, although other CLR numeric types are possible. The exact conversions between script and CLR numeric types depends on the script engine being used.
  • Undefined: Microsoft.ClearScript.Undefined. This refers to JavaScript's undefined value.
  • Void: Microsoft.ClearScript.VoidResult. This is returned when a script forwards the result of a host method that returns no value.
  • Host objects. This includes all .NET types not mentioned above, including value types (enums, structs, etc.), and instances of all other classes. Script code can only create these objects by invoking a host method or constructor. They are returned to the host in their native .NET form.
  • Script objects. This includes all "native" script objects that have no .NET representation. These are returned as instances of System.Dynamic.DynamicObject. C#'s dynamic keyword provides a convenient way to access them:
dynamic x = engine.Evaluate("x = { foo: 123, bar: 456.789 }");
Console.WriteLine(x.bar);
Thanks for your question!
Feb 28, 2013 at 4:00 PM
Edited Feb 28, 2013 at 4:02 PM
Good stuff, I was only wondering, thanks. :)

FYI: That should be in the document also. ;) And while you're at it, update references to "host.newObj" to using just "new".
Coordinator
Feb 28, 2013 at 8:01 PM
You're absolutely right. We need better documentation across the board!
Oct 17, 2013 at 11:46 AM
Edited Oct 17, 2013 at 11:47 AM
public class foo
{
    public double A() { return 0;}  
    public double B() { return 1.1;}
}

engine.AddHostObject("F", new foo());
object result = engine.Evaluate("F.A()");
Console.WriteLine(result.GetType().Name);
result = engine.Evaluate("F.B()");
Console.WriteLine(result.GetType().Name);
foo.A and foo.B are both double.

Why evaluating "F.A" the result is integer and evaluating "F.B" the result is double.

Thank you in advance.
Coordinator
Oct 17, 2013 at 3:41 PM
Greetings!

Script engines usually support just one numeric datatype, but .NET has several, and that creates an ambiguity when it comes to importing numeric values from script. ClearScript's policy is to preserve double values unless they can be converted to int without data loss.

You may be wondering why ClearScript does any data conversion at all. Actually, it aims to do as little data conversion as possible, but this is a special case. This particular conversion is very often desirable because int is an extremely common .NET datatype and is implicitly convertible back to double if that's what's required.

ClearScript's behavior is not ideal in your situation, but in many cases script code uses double because it's the only available numeric datatype, not because it's actually required. Without this conversion many common script-to-host scenarios wouldn't work; e.g., passing an integer literal to a method with an int parameter.

If your application expects a double result from script evaluation, we recommend the following:
var result = Convert.ToDouble(engine.Evaluate(code));
Cheers!
Oct 22, 2013 at 3:29 PM
How can I determine returned "Script objects" type Date,Array, plain object etc.
Coordinator
Oct 22, 2013 at 8:01 PM
Hi luboid!

One way to do this would be to leverage the script engine:
dynamic getObjType = engine.Evaluate(@"
    (function (obj) {
        var type = typeof obj;
        if (type === 'object')
            return obj.constructor.name;
        return type;
    })
");
and then:
var result = engine.Evaluate(code);
if (getObjType(result) == "Date")
{
    // do something
}
Note that this doesn't work with JScript because it doesn't support Function.name, but that can be worked around.

Good luck!