從JavaScript調(diào)用單個.NET方法
您可以使用SetGlobalFunctionAPI
從JavaScript
調(diào)用任何.NET
唱凯。例如:
var engine = new Jurassic.ScriptEngine();
engine.SetGlobalFunction("test", new Func<int, int, int>((a, b) => a + b));
Console.WriteLine(engine.Evaluate<int>("test(5, 6)"));
此代碼將向控制臺輸出"11"
羡忘。
請注意以下幾點:
- 必須全部支持委托參數(shù)類型和返回類型。
- 在提供的委托中引發(fā)的異常無法在
JavaScript
中捕獲(除非它是JavaScriptException
)磕昼。 - 由于安全限制卷雕,以上示例在
Silverlight
中不起作用。要解決此問題票从,請將委托傳遞給公共方法漫雕。
從.NET調(diào)用JavaScript函數(shù)
您也可以從.NET調(diào)用JavaScript函數(shù)。
var engine = new Jurassic.ScriptEngine();
engine.Evaluate("function test(a, b) { return a + b }");
Console.WriteLine(engine.CallGlobalFunction<int>("test", 5, 6));
此代碼將"11"
輸出到控制臺峰鄙。
將.NET類暴露給JavaScript
Building a property bag class
首先,讓我們創(chuàng)建一個包含幾個屬性的類浸间。
using Jurassic;
using Jurassic.Library;
public class AppInfo : ObjectInstance
{
public AppInfo(ScriptEngine engine)
: base(engine)
{
// Read-write property (name).
//類索引器可用于創(chuàng)建讀寫屬性。
this["name"] = "Test Application";
// Read-only property (version).
//`DefineProperty`可用于創(chuàng)建只讀屬性
this.DefineProperty("version", new PropertyDescriptor(5, PropertyAttributes.Sealed), true);
}
}
在此示例中,有幾件事要注意:
- 暴露給
JavaScript
的類需要繼承Jurassic.Library.ObjectInstance
吟榴。 - 將
ScriptEngine
傳遞給基類構(gòu)造函數(shù)意味著該對象將沒有原型魁蒜。因此,常規(guī)功能(hasOwnProperty,toString)
將不可用。 - 類索引器可用于創(chuàng)建讀寫屬性吩翻。
-
DefineProperty
可用于創(chuàng)建只讀屬性兜看。
這是有關(guān)如何創(chuàng)建和使用新類的示例:
var engine = new Jurassic.ScriptEngine();
engine.SetGlobalValue("appInfo", new AppInfo(engine));
Console.WriteLine(engine.Evaluate<string>("appInfo.name + ' ' + appInfo.version"));
Building a class with static functions
下一步是使用靜態(tài)函數(shù)創(chuàng)建一個類,類似于內(nèi)置Math
對象的工作方式。例如,假設您要使用log10函數(shù)創(chuàng)建一個新的Math2
對象:
using Jurassic;
using Jurassic.Library;
public class Math2 : ObjectInstance
{
public Math2(ScriptEngine engine)
: base(engine)
{
this.PopulateFunctions();
}
[JSFunction(Name = "log10")]
public static double Log10(double num)
{
return Math.Log10(num);
}
}
請注意以下幾點:
- PopulateFunctions 在類中搜索[JSFunction]屬性,并為找到的每個屬性創(chuàng)建一個函數(shù)狭瞎。
- [JSFunction]屬性允許JavaScript函數(shù)名稱與.NET方法名稱不同细移。
- 參數(shù)類型和返回類型必須在[支持的類型|支持的類型]列表中。
- 使用[JSProperty]屬性裝飾屬性可將屬性作為訪問者公開給腳本脚作。因此,您可以在CLR中編寫帶有支持者的屬性,或在CLR代碼中設置只讀屬性葫哗。
這是有關(guān)如何創(chuàng)建和使用新類的示例:
var engine = new Jurassic.ScriptEngine();
engine.SetGlobalValue("math2", new Math2(engine));
Console.WriteLine(engine.Evaluate<double>("math2.log10(1000)"));
Building an instance class
可以實例化的對象(例如內(nèi)置的Number,String,Array和RegExp對象)需要兩個.NET類,一個用于構(gòu)造函數(shù),一個用于實例。例如,讓我們制作一個與.NET Random類類似的JavaScript對象(帶有種子,因為JavaScript不支持該對象):
using Jurassic;
using Jurassic.Library;
public class RandomConstructor : ClrFunction
{
public RandomConstructor(ScriptEngine engine)
: base(engine.Function.InstancePrototype, "Random", new RandomInstance(engine.Object.InstancePrototype))
{
}
[JSConstructorFunction]
public RandomInstance Construct(int seed)
{
return new RandomInstance(this.InstancePrototype, seed);
}
}
public class RandomInstance : ObjectInstance
{
private Random random;
public RandomInstance(ObjectInstance prototype)
: base(prototype)
{
this.PopulateFunctions();
this.random = new Random(0);
}
public RandomInstance(ObjectInstance prototype, int seed)
: base(prototype)
{
this.random = new Random(seed);
}
[JSFunction(Name = "nextDouble")]
public double NextDouble()
{
return this.random.NextDouble();
}
}
請注意以下幾點:
- 您需要兩個類-一個是構(gòu)造函數(shù)(即調(diào)用new的函數(shù)對象),另一個是實例對象球涛。
- ClrFunction基類需要三個參數(shù):函數(shù)對象的原型,函數(shù)的名稱和使用該函數(shù)創(chuàng)建的任何實例的原型劣针。
- [JSConstructorFunction]屬性標記使用新運算符時調(diào)用的方法。您也可以使用[JSCallFunction]標記直接調(diào)用該函數(shù)時所調(diào)用的方法亿扁。
- RandomInstance類具有兩個構(gòu)造函數(shù)-一個用于初始化原型,一個用于初始化所有其他實例捺典。 PopulateFunctions只能從原型對象中調(diào)用。
這是有關(guān)如何創(chuàng)建和使用新類的示例:
var engine = new Jurassic.ScriptEngine();
engine.SetGlobalValue("Random", new RandomConstructor(engine));
Console.WriteLine(engine.Evaluate<double>("var rand = new Random(1000); rand.nextDouble()"));
這將向控制臺輸出"0.151557459100875"(由于我們使用的是種子,因此每次對nextDouble()的第一次調(diào)用都相同从祝。)
這個例子涉及更多,但是它支持所有高級JavaScript概念:
- rand支持內(nèi)置的Object函數(shù)(hasOwnProperty,toString等)襟己。
- rand利用原型繼承引谜。在這種情況下,您具有以下原型鏈:
random instance (with no properties) -> random prototype (with nextDouble defined) -> object prototype -> null
.
從自定義源加載腳本
如果要執(zhí)行的腳本不在文件中,并且不想將其加載到字符串中擎浴,則可以創(chuàng)建一個custom ScriptSource
员咽。以下示例顯示了如何完成此操作:
/// <summary>
/// Represents a string containing script code.
/// </summary>
public class StringScriptSource : ScriptSource
{
private string code;
/// <summary>
/// Creates a new StringScriptSource instance.
/// </summary>
/// <param name="code"> The script code. </param>
public StringScriptSource(string code)
{
if (code == null)
throw new ArgumentNullException("code");
this.code = code;
}
/// <summary>
/// Gets the path of the source file (either a path on the file system or a URL). This
/// can be <c>null</c> if no path is available.
/// </summary>
public override string Path
{
get { return null; }
}
/// <summary>
/// Returns a reader that can be used to read the source code for the script.
/// </summary>
/// <returns> A reader that can be used to read the source code for the script, positioned
/// at the start of the source code. </returns>
/// <remarks> If this method is called multiple times then each reader must return the
/// same source code. </remarks>
public override TextReader GetReader()
{
return new StringReader(this.code);
}
}
線程與并發(fā)
侏羅紀不是線程安全的。但是贮预,它也不使用任何線程局部或全局狀態(tài)贝室。因此,只要確保沒有一次從多個線程調(diào)用任何Jurassic
對象仿吞,它將起作用滑频。確保這一點的最簡單方法是使用多個腳本引擎(每個線程一個是理想的)。由于非原始對象綁定到單個腳本引擎唤冈,因此每個腳本引擎都完全相互隔離峡迷。這確實使腳本引擎之間難以共享數(shù)據(jù)。共享數(shù)據(jù)的一種方法是將其序列化為字符串你虹,然后在線程之間傳遞(JSON
對象可用于序列化JavaScript
對象)绘搞。