目錄
1.Getting Started
步驟1:在 IDE 中引入 MoonSharp
步驟2:引入命名空間
步驟3:調用腳本
步驟4:運行代碼
2.Keeping a Script around
步驟1:復現前教程所有操作
步驟2:改為創建Script對象
步驟3:訪問全局環境
步驟4:直接調用函數
3.DynValue revealed
步驟1:重新執行你在上一個教程中的所有操作
步驟2:將 fact 函數存入 DynValue
步驟3:將數字存入 DynValue
步驟 4:了解 DataType(s)
步驟 5:元組
4.Calling back C#
步驟 1:永遠不要厭倦階乘
步驟 2:自定義乘法函數
返回一系列數字
返回表格
接收一個表
5.Auto-conversions
自定義轉換器
CLR 類型到 MoonSharp 類型的自動轉換
MoonSharp 類型到 CLR 類型的標準自動轉換
MoonSharp 類型到 CLR 類型的受限自動轉換
文檔地址:
MoonSharp
1.Getting Started
您的第一個 MoonSharp 項目的快速指南
本教程將帶你初步體驗 MoonSharp 的簡潔與強大。雖然 MoonSharp 有更優的使用方式,但這是最基礎的一種。其他教程會深入探討如何充分發揮 MoonSharp 的潛力。現在,讓我們開始吧!
關于語言支持的說明
本網站大多數教程僅提供 C# 示例,但本頁會為 VB.NET 用戶提供一些指引。
MoonSharp 兼容所有 CLR 語言(C#、VB.NET、C++/CLI、F#、Boo 等),理論上也支持DLR語言(如 IronPython、IronRuby)。但由于維護多語言示例的工作量較大,后續教程僅提供 C# 示例(本入門頁含 VB.NET)。
大多數教程的代碼可在 GitHub 的示例項目中找到。
學習前提:需熟悉Lua和至少一門.NET語言(推薦 C#),否則可能難以理解示例。
步驟1:在 IDE 中引入 MoonSharp
根據使用的IDE(Visual Studio、MonoDevelop、SharpDevelop、Unity)選擇以下方式:
Visual Studio(通過 NuGet)
1.在包管理器控制臺輸入:
PM> Install-Package MoonSharp ?
2.或右鍵“引用”->“管理NuGet包”->搜索“MoonSharp”并安裝。
Xamarin Studio(通過NuGet)
菜單欄選擇“項目”->“添加NuGet包”->搜索“MoonSharp”并安裝。
其他IDE(手動添加)
將 MoonSharp 發行包中對應平臺的 MoonSharp.Interpreter.dll 添加為項目依賴。
Unity
1.推薦方式:通過Asset Store安裝(待審核后在此鏈接提供)。
2.手動方式:
將 interpreter/net35 目錄下的 MoonSharp.Interpreter.dll 放入 Assets/Plugins。
若需支持 Windows Store/WP:
?? ?將 interpreter/portable-net40 下的 DLL放入 Assets/Plugins/WSA。
?? ?參考此指南配置。鏈接
3.IL2CPP項目:
在 Assets 目錄下創建/編輯 link.xml,內容如下:
<linker> ?<assembly fullname="MoonSharp.Interpreter"> ?<type fullname="MoonSharp.*" preserve="all" /> ?</assembly> ?
</linker> ?
步驟2:引入命名空間
在代碼頂部添加:
C#
using MoonSharp.Interpreter; ?
VB.NET
Imports MoonSharp.Interpreter ?
步驟3:調用腳本
以下示例演示如何用MoonSharp計算階乘:
C#
double MoonSharpFactorial()
{string script = @" -- defines a factorial functionfunction fact (n)if (n == 0) thenreturn 1elsereturn n*fact(n - 1)endendreturn fact(5)";DynValue res = Script.RunString(script);return res.Number;
}
VB.NET
Function MoonSharpFactorial() As Double' VB.NET is not very strong at embedded newlines...Dim scriptCode As String = "-- defines a factorial function" & vbCrLf &"function fact (n)" & vbCrLf & _"if (n == 0) then" & vbCrLf & _"return 1" & vbCrLf & _"else" & vbCrLf & _"return n*fact(n - 1)" & vbCrLf & _"end" & vbCrLf & _"end" & vbCrLf & _"return fact(5)" & vbCrLfDim res As DynValue = Script.RunString(scriptCode)Return res.Number
End Function
步驟4:運行代碼
在代碼中調用MoonSharpFactorial()即可執行腳本。現在,你可以繼續探索其他教程了!
?
2.Keeping a Script around
言語易逝,文字永存。
在之前的教程中,你首次接觸了 MoonSharp:將腳本放入字符串中運行并獲取輸出。雖然偶爾有用,但大多數實際用例需要的互操作性需要 CLR 代碼與 MoonSharp 更深度的集成。
步驟1:復現前教程所有操作
認真地說,雖然我們在這里學習的是(稍微)更高級的概念,但你最初的嘗試幾乎無需改動。這正是一個極好的起點。
步驟2:改為創建Script對象
首先要做的更改是創建一個腳本對象,而不是使用靜態方法之一。這并非什么難事,但它為我們接下來的發展奠定了基礎。
double MoonSharpFactorial()
{string scriptCode = @" -- defines a factorial functionfunction fact (n)if (n == 0) thenreturn 1elsereturn n*fact(n - 1)endendreturn fact(5)";Script script = new Script();DynValue res = script.DoString(scriptCode);return res.Number;
}
步驟3:訪問全局環境
現在有了腳本對象,我們可以修改函數運行的全局環境。例如,改變階乘函數的輸入參數,讓程序能指定計算目標數值的階乘。
?
double MoonSharpFactorial()
{string scriptCode = @" -- defines a factorial functionfunction fact (n)if (n == 0) thenreturn 1elsereturn n*fact(n - 1)endendreturn fact(mynumber)";Script script = new Script();script.Globals["mynumber"] = 7;DynValue res = script.DoString(scriptCode);return res.Number;
}
通過簡單的 script.Globals 表引用語法,我們實現了向 MoonSharp 腳本注入數值。實際上不僅能傳遞數字,后續還將演示如何傳遞函數和對象,但現階段我們暫限于數字、布爾值和字符串。
步驟4:直接調用函數
我們學習了如何讓 MoonSharp 計算從外部選擇的數字的階乘。但是,以這種方式完成,感覺像是一個骯臟的黑客行為(盡管如此,這是一項重要的技術,我們將經常使用)。
下面是如何從C#調用Lua函數。
double MoonSharpFactorial2()
{string scriptCode = @" -- defines a factorial functionfunction fact (n)if (n == 0) thenreturn 1elsereturn n*fact(n - 1)endend";Script script = new Script();script.DoString(scriptCode);DynValue res = script.Call(script.Globals["fact"], 4);return res.Number;
}
我們來看看具體做了哪些調整。
首先,我們刪除了腳本結尾的 return 語句——這個語句本來可以保留,但由于我們需要通過自定義參數調用 fact 函數,保留它反而會導致冗余。
此時,script.DoString(...)? 的調用將會執行整個腳本文件,在全局環境中留下一個完整可用的 fact 函數。
隨后我們添加了這一行代碼:
DynValue res = script.Call(script.Globals["fact"], 4);
這段代碼會從腳本的全局環境中獲取 fact 函數,并以參數4進行調用。
雖然存在更高效的實現方式(特別是在性能方面),但如果您不需要在時間敏感的循環中進行大量調用,這無疑是最簡單的解決方案(不過存在一定的類型安全隱患)。
值得注意的是,fact 函數可以任意次數被調用——因為 Script 會保留其運行狀態,并隨時準備好被反復執行。
3.DynValue revealed
一切皆是 DynValue,DynValue 即一切。
DynValue 概念實際上是 MoonSharp 的核心基礎,盡管到目前為止我們幾乎沒有涉及太多,但事實上,想要深入了解而不觸及這一主題是不太可能的。
如標題所述,MoonSharp 中的(幾乎)所有內容都是 DynValue 對象的實例。一個 DynValue 代表腳本中的一個值,無論其類型如何,因此它可以是一個表、一個函數、一個數字、一個字符串或其他任何東西。
那么,讓我們從最新的教程步驟開始,并將其改為使用 DynValue。
步驟1:重新執行你在上一個教程中的所有操作
我們再次從上一個教程的最后一步開始。你已經完成了吧?
你可以在這里獲取參考文檔。
步驟2:將 fact 函數存入 DynValue
第一個改動是我們以不同的方式獲取 fact 變量:
double MoonSharpFactorial()
{string scriptCode = @" -- defines a factorial functionfunction fact (n)if (n == 0) thenreturn 1elsereturn n*fact(n - 1)endend";Script script = new Script();script.DoString(scriptCode);DynValue luaFactFunction = script.Globals.Get("fact");DynValue res = script.Call(luaFactFunction, 4);return res.Number;
}
好的,讓我們在這一行花點時間:
DynValue luaFactFunction = script.Globals.Get("fact");
這樣可以從腳本的全局作用域中獲取 fact 函數。與索引器屬性不同,「Get」方法會直接返回一個「DynValue」類型,而索引器則會嘗試將其轉換為「System.Object」。在本例中,由于我們需要獲取的是「DynValue」類型,因此選擇使用「Get」方法。
步驟3:將數字存入 DynValue
如果我們希望避免額外的類型轉換,可以直接以「DynValue」形式傳遞數字,而無需依賴「Call」方法提供的隱式轉換。雖然當前場景中這不是必需的,但在其他情況下可能會用到,畢竟并非所有操作都會自動幫你完成類型轉換!
double MoonSharpFactorial2()
{string scriptCode = @" -- defines a factorial functionfunction fact (n)if (n == 0) thenreturn 1elsereturn n*fact(n - 1)endend";Script script = new Script();script.DoString(scriptCode);DynValue luaFactFunction = script.Globals.Get("fact");DynValue res = script.Call(luaFactFunction, DynValue.NewNumber(4));return res.Number;
}
所以,我們用以下內容替換了我們的數字:
DynValue.NewNumber(4)
DynValue 有許多工廠方法,都以 "New" 開頭(如 NewString、NewNumber、NewBoolean 等),可用于從頭開始構建我們的值。
它還有一個方便的 FromObject 方法,可以從對象創建 DynValue,這正是 Call 在幕后使用的方法,以簡化我們的工作。
步驟 4:了解 DataType(s)
在 DynValue 中,最重要的屬性之一是 Type。
Type 屬性是一個枚舉,告訴我們 DynValue 中包含了什么類型的數據。
每當我們想知道 DynValue 中包含了什么,我們都可以查詢 Type 屬性:
// Create a new number
DynValue v1 = DynValue.NewNumber(1);
// and a new string
DynValue v2 = DynValue.NewString("ciao");
// and another string using the automagic converters
DynValue v3 = DynValue.FromObject(new Script(), "hello");// This prints Number - String - String
Console.WriteLine("{0} - {1} - {2}", v1.Type, v2.Type, v3.Type);
// This prints Number - String - Some garbage number you shouldn't rely on to be 0
Console.WriteLine("{0} - {1} - {2}", v1.Number, v2.String, v3.Number);
重要的是要知道,DynValue 的某些屬性只有在值是給定類型時才有意義。例如,只有當類型為 DataType.Number 時,Number 屬性才能保證有意義的值,String 屬性也是如此。
除非你確定 DynValue 包含什么,否則在使用其屬性之前,請務必檢查 DynValue 的 Type。假設 DynValue 包含一個給定類型,而它實際上包含另一個類型,這是錯誤和問題的常見來源。
步驟 5:元組
正如你(應該)知道的,Lua 可以從函數(以及其他情況)返回多個值。
為了處理這種情況,使用了一種特殊的 DynValue 類型(DataType.Tuple)。元組有一個 Tuple 屬性,它是 DynValue 對象的數組,這些對象是元組的成員。
這比聽起來更簡單:
DynValue ret = Script.RunString("return true, 'ciao', 2*3");// prints "Tuple"
Console.WriteLine("{0}", ret.Type);// Prints:
// Boolean = true
// String = "ciao"
// Number = 6
for (int i = 0; i < ret.Tuple.Length; i++)Console.WriteLine("{0} = {1}", ret.Tuple[i].Type, ret.Tuple[i]);
結語
關于 DynValue 的介紹就到這里。還有很多需要學習的內容,但這些應該足以讓你入門了。
請記住這些內容,因為這是一切的核心。
4.Calling back C#
但也支持 F# 和 VB.NET 和 C++/CLI 和 Boo 等等...
腳本在應用程序中非常有用,因為它們可以從包含應用程序本身實現的構建塊開始,自定義業務邏輯。無論您是在商業應用程序、視頻游戲還是某種工具中嵌入腳本,您的首要關注點是腳本和應用程序的互操作性以及兩者之間的對象共享(在某種意義上)。
而過程編程中的基本構建塊是函數。
步驟 1:永遠不要厭倦階乘
讓我們從到目前為止我們使用的標準階乘腳本開始:
private static double CallbackTest()
{string scriptCode = @" -- defines a factorial functionfunction fact (n)if (n == 0) thenreturn 1elsereturn n * fact(n - 1);endend";Script script = new Script();script.DoString(scriptCode);DynValue res = script.Call(script.Globals["fact"], 4);return res.Number;
}
步驟 2:自定義乘法函數
好的,假設我們希望乘法在宿主應用程序的 API 函數中實現。在這種情況下,這樣做顯然沒有任何目的,但我們在這里是為了學習,所以讓我們假裝這是一個好主意。
private static int Mul(int a, int b)
{return a * b;
}private static double CallbackTest()
{string scriptCode = @" -- defines a factorial functionfunction fact (n)if (n == 0) thenreturn 1elsereturn Mul(n, fact(n - 1));endend";Script script = new Script();script.Globals["Mul"] = (Func<int, int, int>)Mul;script.DoString(scriptCode);DynValue res = script.Call(script.Globals["fact"], 4);return res.Number;
}
就是這樣!
script.Globals["Mul"] = (Func<int, int, int>)Mul;
這將全局環境中的 Mul 變量設置為指向應用程序的 Mul 委托。我們在這里將委托強制轉換為它的 Func<int, int, int> 類型以取悅 C# 編譯器 - 無論您使用什么技術將委托強制轉換為 System.Object 都可以。
另外,請注意,我們將方法定義為靜態的,但在這種情況下,它們完全不需要是靜態的;實例方法也可以使用。
返回一系列數字
問題:有一個API函數,它返回一個整數序列。腳本將對收到的數字求和,并返回總數。
private static IEnumerable<int> GetNumbers()
{for (int i = 1; i <= 10; i++)yield return i;
}private static double EnumerableTest()
{string scriptCode = @" total = 0;for i in getNumbers() dototal = total + i;endreturn total;";Script script = new Script();script.Globals["getNumbers"] = (Func<IEnumerable<int>>)GetNumbers;DynValue res = script.DoString(scriptCode);return res.Number;
}
在這里,也沒有太難的地方。你可以看到如何將一個 IEnumerable(或 IEnumerator)即時轉換為 Lua 迭代器,以便腳本運行。
還要注意,腳本中直接包含了可執行代碼,因此在 DoString 時刻就可以訪問 getNumbers 方法,無需進行 Call.. 調用。記住這一點,DoString 和 DoFile 將立即執行腳本中包含的代碼!
還有一點必須注意。MoonSharp 能夠轉換 System.Collections.IEnumerable 和 System.Collections.IEnumerator 類型的迭代器。也就是說,非泛型的變體。如果由于某種原因你實現了一個泛型迭代器而沒有實現非泛型迭代器,那么迭代器將無法工作。所有標準的集合類型和迭代器方法,如上面的方法,默認實現了非泛型變體,所以不需要太擔心。
返回表格
問題:有一個API函數,這次返回一個整數序列,存儲在一個表格中。
private static List<int> GetNumberList()
{List<int> lst = new List<int>();for (int i = 1; i <= 10; i++)lst.Add(i);return lst;
}private static double TableTest1()
{string scriptCode = @" total = 0;tbl = getNumbers()for _, i in ipairs(tbl) dototal = total + i;endreturn total;";Script script = new Script();script.Globals["getNumbers"] = (Func<List<int>>)GetNumberList;DynValue res = script.DoString(scriptCode);return res.Number;
}
在這里,我們可以看到 List<int> 是如何自動轉換為 Lua 表的!請注意,生成的表將像 Lua 表通常那樣以1為索引。
然而,我們可以做得更好。我們可以直接在函數內部構建一個 Lua 表:
private static Table GetNumberTable(Script script)
{Table tbl = new Table(script);for (int i = 1; i <= 10; i++)tbl[i] = i;return tbl;
}private static double TableTest2()
{string scriptCode = @" total = 0;tbl = getNumbers()for _, i in ipairs(tbl) dototal = total + i;endreturn total;";Script script = new Script();script.Globals["getNumbers"] = (Func<Script, Table>)(GetNumberTable);DynValue res = script.DoString(scriptCode);return res.Number;
}
您可以看到使用 Table 對象操作表是多么容易。
但是有兩點需要注意:
要創建一個新的 Table 對象,您必須有一個對正在執行的腳本的引用
如果在 CLR 函數中有一個 Script 參數可供 Lua 腳本使用,MoonSharp 將為您填充它。這也適用于(不太可能以這種方式使用的)ScriptExecutionContext 和 CallbackArguments 類型。如果您不知道這些是做什么的,不用擔心,它們不是讓 MoonSharp 基本工作所必需的!
作為一個好的實踐,如果可以的話,總是保留 Script 對象。有些事情(比如創建表)只能使用 Script 對象來完成。
接收一個表
一個表會自動轉換為 List<T>。例如:
public static double TableTestReverse()
{string scriptCode = @" return dosum { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }";Script script = new Script();script.Globals["dosum"] = (Func<List<int>, int>)(l => l.Sum());DynValue res = script.DoString(scriptCode);return res.Number;
}
但是,這可能會在某些平臺(比如 iOS)上造成問題。有很多方法可以解決這個問題(你會在其他教程中看到),但可以說,以下方法沒有任何問題,而且速度更快:
public static double TableTestReverseSafer()
{string scriptCode = @" return dosum { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }";Script script = new Script();script.Globals["dosum"] = (Func<List<object>, int>)(l => l.OfType<int>().Sum());DynValue res = script.DoString(scriptCode);return res.Number;
}
另一種更快的方法是使用 Table 對象:
static double Sum(Table t)
{var nums = from v in t.Valueswhere v.Type == DataType.Numberselect v.Number;return nums.Sum();
}private static double TableTestReverseWithTable()
{string scriptCode = @" return dosum { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }";Script script = new Script();script.Globals["dosum"] = (Func<Table, double>)Sum;DynValue res = script.DoString(scriptCode);return res.Number;
}
但在這里,我們必須處理 DynValue(s)。
要理解所有這些,我們需要更深入地了解 MoonSharp 如何將 Lua 類型映射到 C# 類型,反之亦然。我們將在下一部分中詳細討論。
5.Auto-conversions
這次沒有代碼。
在深入探討 MoonSharp 和 CLR 集成之前,我們需要明確類型是如何來回映射的。遺憾的是,反向映射與正向映射有很大不同,因此我們將分別分析這兩種情況。
你可能會問,這是不是有點太復雜了?
當然復雜。自動化的東西很好,但當它們失敗時,失敗的方式卻非常復雜。當有疑問或事情變得過于復雜時,你需要簡化事情。
有兩種方法:要么直接使用 DynValue,要么使用自定義轉換器。
這兩種解決方案不僅能讓你獲得理智和簡單,而且在速度上也明顯快于自動轉換!
自定義轉換器
可以自定義轉換過程,但設置是全局的,會影響所有腳本。
要自定義轉換,只需將適當的回調設置為 Script.GlobalOptions.CustomConverters。
例如,如果我們希望在從 CLR 轉換為腳本時,將所有 StringBuilder 對象轉換為大寫字符串,可以這樣做:
Script.GlobalOptions.CustomConverters.SetClrToScriptCustomConversion<StringBuilder>(v => DynValue.NewString(v.ToString().ToUpper()));
如果我們想自定義所有表格在與 IList<int> 匹配時的轉換方式,我們可以這樣寫:
Script.GlobalOptions.CustomConverters.SetScriptToClrCustomConversion(DataType.Table, typeof(IList<int>),v => new List<int>() { ... });
如果一個轉換器返回 null,系統會表現得就像沒有自定義轉換器存在一樣,并嘗試進行自動轉換。
CLR 類型到 MoonSharp 類型的自動轉換
這個轉換適用于以下情況:
? 從腳本調用的函數返回對象時
? 從用戶數據的屬性返回對象時 ?
? 使用索引運算符在表中設置值時
? 調用 DynValue.FromObject 時
? 使用任何以 System.Object 代替 DynValue 作為參數的函數重載時
這個轉換實際上非常簡單。下表解釋了具體的轉換規則:
CLR type | C# friendly name | Lua type | Notes |
---|---|---|---|
void | (no value) | This can be applied to return values of methods only. 翻譯:這只能應用于方法的返回值。 | |
null | nil | Any null will be converted to nil. 翻譯:任何null都將轉換為nil。 | |
MoonSharp.Interpreter.DynValue | * | The DynValue is passed through. 翻譯:DynValue 被傳遞了。 | |
System.SByte | sbyte | number | |
System.Byte | byte | number | |
System.Int16 | short | number | |
System.UInt16 | ushort | number | |
System.Int32 | int | number | |
System.UInt32 | uint | number | |
System.Int64 | long | number | The conversion can lead to a silent precision loss. 翻譯:轉換可能導致精度無聲地丟失。 |
System.UInt64 | ulong | number | The conversion can lead to a silent precision loss. 翻譯:轉換可能導致精度無聲地丟失。 |
System.Single | float | number | |
System.Decimal | decimal | number | The conversion can lead to a silent precision loss. 翻譯:轉換可能導致精度無聲地丟失。 |
System.Double | double | number | |
System.Boolean | bool | boolean | |
System.String | string | string | |
System.Text.StringBuilder | string | ||
System.Char | char | string | |
MoonSharp.Interpreter.Table | table | ||
MoonSharp.Interpreter.CallbackFunction | function | ||
System.Delegate | function | ||
System.Object | object | userdata | Only if the type has been registered for userdata. 翻譯:只有當該類型已經為 userdata 注冊過,才可以這樣做。 |
System.Type | userdata | Only if the type has been registered for userdata, static members access. 翻譯:只有當類型已經為 userdata 注冊時,才可以訪問靜態成員。 | |
MoonSharp.Interpreter.Closure | function | ||
System.Reflection.MethodInfo | function | ||
System.Collections.IList | table | The resulting table will be indexed 1-based. All values are converted using these rules. 翻譯:生成的表將使用從1開始的索引。所有的值都會按照以下規則進行轉換。 | |
System.Collections.IDictionary | table | All keys and values are converted using these rules. 翻譯:所有鍵和值都會使用這些規則進行轉換。 | |
System.Collections.IEnumerable | iterator | All values are converted using these rules. 翻譯:所有值均依下列規則進行轉換。 | |
System.Collections.IEnumerator | iterator | All values are converted using these rules. 翻譯:所有值均依下列規則進行轉換。 |
這包括對集合的相當全面的覆蓋,因為大多數集合都實現了 IList、IDictionary、IEnumerable 和/或 IEnumerator 接口。如果你正在編寫自己的集合,請記得實現這些非泛型接口中的一個。
任何不能使用此邏輯轉換的值都將拋出 ScriptRuntimeException。
MoonSharp 類型到 CLR 類型的標準自動轉換
相反的轉換要復雜得多。實際上,存在兩條不同的轉換路徑--"標準"路徑和"受限"路徑。當你要求將一個 DynValue 轉換為對象而不指定你實際想要接收什么時,應用第一種路徑,而當有一個目標 System.Type 要匹配時,則應用另一種路徑。
這在以下情況下使用:
- 調用 DynValue.ToObject 時
- 使用索引器從表中檢索值時
- 在受限轉換的一些特定子情況下(見下文)
這里我們看到默認轉換。它實際上很簡單:
MoonSharp type | CLR type | Notes |
---|---|---|
nil | null | Applied to every value which is nil. 翻譯:應用于每個值為 nil 的情況。 |
boolean | System.Boolean | |
number | System.Double | |
string | System.String | |
function | MoonSharp.Interpreter.Closure | If DataType is Function. 翻譯:如果數據類型是函數(Function)。 |
function | MoonSharp.Interpreter.CallbackFunction | If DataType is ClrFunction. 翻譯:如果數據類型是 CLR 函數(ClrFunction)。 |
table | MoonSharp.Interpreter.Table | |
tuple | MoonSharp.Interpreter.DynValue[] | |
userdata | (special) | Returns the object stored in userdata. If a "static" userdata, the Type is returned. 翻譯:如果是存儲在 userdata 中的對象,此方法會返回該對象。如果是“靜態”userdata,則返回其類型(Type)。 |
無法使用此邏輯轉換的每個值都將拋出 ScriptRuntimeException 異常。
MoonSharp 類型到 CLR 類型的受限自動轉換
非常感謝您提供這些關于 MoonSharp 類型轉換的詳細信息!我來總結一下要點:
MoonSharp 類型到 CLR 類型的受限自動轉換比默認轉換要復雜得多。它發生在需要將 MoonSharp 值存儲到給定類型的 CLR 變量中的情況下,轉換方式幾乎有無限多種。
特殊情況:
- 如果目標類型是 DynValue,則不進行轉換,返回原始值。
- 如果目標類型是 object,則應用默認轉換。
- 如果要映射 nil 值,則 null 映射到引用類型和可空值類型。某些情況下會嘗試匹配默認值。否則拋出異常。
- 如果沒有提供值,則盡可能使用默認值。
數據類型轉換:
- 字符串可轉換為 String, StringBuilder 或 Char
- 布爾值可轉換為 Boolean 及其可空版本,也可轉換為字符串類型
- 數字可轉換為 SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Decimal, Double 及其可空版本,也可轉換為字符串類型
- 函數轉換為 Closure, ScriptFunctionDelegate, ClrFunction 或 Func 委托
- 非靜態的 userdata 如果類型兼容則可轉換。也可通過 ToString() 轉換為字符串類型
- 表可轉換為 Table, Dictionary, List, 數組等多種集合類型,但轉換到泛型和類型化數組有一些限制,可能會有性能和兼容性問題
總之,MoonSharp 在類型轉換上非常靈活,但復雜類型的轉換可能存在一些問題。必要時可以添加自定義轉換器來解決。在面向 AOT 平臺時,要特別小心值類型的泛型可能引入的不兼容問題。
end