Firstly, I hope Task can be directly await in script without calling ToPromise() in addition, so I wrote the code below which provided then method for await to call:
public static class TaskExtension
{
public static dynamic then(this Task task, dynamic ok, dynamic failed = null)
{
dynamic promise = task.ToPromise();
return promise.then(ok, failed);
}
}
However, after invoking engine.AddHostType(typeof(TaskExtension));, using await to any host object which does not have then method(or await any promise which return such object after resolving, or simply use a promise resolved by such object) will raise exception. Here are one example:
This code output no error:
public class Bird
{
}
class Program
{
static void Main(string[] args)
{
V8ScriptEngine engine = new V8ScriptEngine();
engine.AddHostType(typeof(Console));
engine.AddHostObject("bird", new Bird());
engine.Execute("Promise.resolve(bird).then(e=>{Console.WriteLine('no error');},e=>{Console.WriteLine(e.toString());})");
}
}
This code output Error: 'ExampleApp.Bird' does not contain a definition for 'then':
public static class TaskExtension
{
public static dynamic then(this Task task, dynamic ok, dynamic failed = null)
{
dynamic promise = task.ToPromise();
return promise.then(ok, failed);
}
}
public class Bird
{
}
class Program
{
static void Main(string[] args)
{
V8ScriptEngine engine = new V8ScriptEngine();
engine.AddHostType(typeof(Console));
engine.AddHostType(typeof(TaskExtension));
engine.AddHostObject("bird", new Bird());
engine.Execute("Promise.resolve(bird).then(e=>{Console.WriteLine('no error');},e=>{Console.WriteLine(e.toString());})");
}
}
In fact, this script engine will get then property of resolved value, and check whether this property is function. If so, the engine regard such value as another promise and call the property internally.
Here are an example which show the problem more clearly:
public class Bird
{
}
public class Dog
{
}
public static class BirdExtension
{
public static void fly(this Bird bird)
{
// fly
}
}
class Program
{
static void Main(string[] args)
{
V8ScriptEngine engine = new V8ScriptEngine();
engine.AddHostType(typeof(Console));
engine.AddHostObject("dog", new Dog());
engine.Execute("Console.WriteLine(typeof dog.fly);");
engine.AddHostType(typeof(BirdExtension));
engine.Execute("Console.WriteLine(typeof dog.fly);");
engine.Execute("try{ dog.fly(); }catch(e){ Console.WriteLine(e.toString()) }");
}
}
The output is
undefined
function
Error: 'ExampleApp.Dog' does not contain a definition for 'fly'
which show extension method will be added to all host object, although some of them actually cannot invoke them.
In my opinion, this is a bug caused by GetAllMethodNames method in https://github.com/microsoft/ClearScript/blob/master/ClearScript/HostItem.cs.
In this method, all extension method name will be added to result without checking the type of this arg.
By the way, could you please provide a optional feature to convert Task and Promise automatically(without calling ToTask and ToPromise) like V8ScriptEngineFlags.EnableDateTimeConversion do for DateTime and Date?
Or more generally, can we custom the process of marshaling object?
Firstly, I hope
Taskcan be directlyawaitin script without callingToPromise()in addition, so I wrote the code below which providedthenmethod forawaitto call:However, after invoking
engine.AddHostType(typeof(TaskExtension));, usingawaitto any host object which does not havethenmethod(or await any promise which return such object after resolving, or simply use a promise resolved by such object) will raise exception. Here are one example:This code output
no error:This code output
Error: 'ExampleApp.Bird' does not contain a definition for 'then':In fact, this script engine will get
thenproperty of resolved value, and check whether this property isfunction. If so, the engine regard such value as another promise and call the property internally.Here are an example which show the problem more clearly:
The output is
which show extension method will be added to all host object, although some of them actually cannot invoke them.
In my opinion, this is a bug caused by
GetAllMethodNamesmethod in https://github.com/microsoft/ClearScript/blob/master/ClearScript/HostItem.cs.In this method, all extension method name will be added to result without checking the type of this arg.
By the way, could you please provide a optional feature to convert Task and Promise automatically(without calling ToTask and ToPromise) like V8ScriptEngineFlags.EnableDateTimeConversion do for DateTime and Date?
Or more generally, can we custom the process of marshaling object?