我正在编写一个C#和JavaScript代码需要协同工作的项目,因此我决定使用CefSharp,因为它保证了最新的JS功能(与WebView相比)。
现在我需要创建一个异步C#方法,它会调用异步JS函数,然后等待它完成。问题是JavaScript没有await
关键字之类的内容,因此所有内容都是根据事件定义的。
这就是Javascript代码的样子:
var name1 = "A";
var name2 = "B";
library.renameObject("A","B");
library.onrename = function(from, to){
if(from === "A"){
//let C# know
}
}
理想情况下,C#代码应该是这样的:
class FooObject
{
string Name;
async Task Rename(string newName)
{
await mainFrame.EvaluateScriptAsync(@"
//The JS code
");
Name = newName;
}
}
起初我以为使用任务/承诺会完成这项工作,但经过一些测试后我发现在JS和C#之间传递对象是不可能的。
这意味着当我尝试将TaskCompletionSource
传递给IJavascriptCallback
时,我得到了
System.NotSupportedException:无法将复杂类型序列化为Cef列表
然后我尝试从JavaScript代码返回Promise
,但在C#中我总是得到null
。
我知道使用反射,代理和Dictionary<int, WeakRef<object>>
我可以提供一个接口,这样就可以从JavaScript中访问任何C#对象,这种方式与使用实际的JS对象无法区分。方法是:
Reflection
创建方法,将唯一键作为参数,并允许读取字段和调用对象的方法RegisterJsObject
Proxy
,并在后台调用暴露的C#方法。这个解决方案的坏消息是,在JavaScript中没有析构函数/终结符,所以我无法控制V8 GC。这意味着C#对象将永远保留在那里(内存泄漏)或过早收集.Net GC(空指针异常)。