MoonSharp 文档一

目录

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 typeC# friendly nameLua typeNotes
void(no value)

This can be applied to return values of methods only.

翻译:这只能应用于方法的返回值。

nullnil

Any null will be converted to nil.

翻译:任何null都将转换为nil。

MoonSharp.Interpreter.DynValue*

The DynValue is passed through.

翻译:DynValue 被传递了。

System.SBytesbytenumber
System.Bytebytenumber
System.Int16shortnumber
System.UInt16ushortnumber
System.Int32intnumber
System.UInt32uintnumber
System.Int64longnumber

The conversion can lead to a silent precision loss.

翻译:转换可能导致精度无声地丢失。

System.UInt64ulongnumber

The conversion can lead to a silent precision loss.

翻译:转换可能导致精度无声地丢失。

System.Singlefloatnumber
System.Decimaldecimalnumber

The conversion can lead to a silent precision loss.

翻译:转换可能导致精度无声地丢失。

System.Doubledoublenumber
System.Booleanboolboolean
System.Stringstringstring
System.Text.StringBuilderstring
System.Charcharstring
MoonSharp.Interpreter.Tabletable
MoonSharp.Interpreter.CallbackFunctionfunction
System.Delegatefunction
System.Objectobjectuserdata

Only if the type has been registered for userdata.

翻译:只有当该类型已经为 userdata 注册过,才可以这样做。

System.Typeuserdata

Only if the type has been registered for userdata, static members access.

翻译:只有当类型已经为 userdata 注册时,才可以访问静态成员。

MoonSharp.Interpreter.Closurefunction
System.Reflection.MethodInfofunction
System.Collections.IListtable

The resulting table will be indexed 1-based. All values are converted using these rules.

翻译:生成的表将使用从1开始的索引。所有的值都会按照以下规则进行转换。

System.Collections.IDictionarytable

All keys and values are converted using these rules.

翻译:所有键和值都会使用这些规则进行转换。

System.Collections.IEnumerableiterator

All values are converted using these rules.

翻译:所有值均依下列规则进行转换。

System.Collections.IEnumeratoriterator

All values are converted using these rules.

翻译:所有值均依下列规则进行转换。

这包括对集合的相当全面的覆盖,因为大多数集合都实现了 IList、IDictionary、IEnumerable 和/或 IEnumerator 接口。如果你正在编写自己的集合,请记得实现这些非泛型接口中的一个。

任何不能使用此逻辑转换的值都将抛出 ScriptRuntimeException。

MoonSharp 类型到 CLR 类型的标准自动转换

相反的转换要复杂得多。实际上,存在两条不同的转换路径--"标准"路径和"受限"路径。当你要求将一个 DynValue 转换为对象而不指定你实际想要接收什么时,应用第一种路径,而当有一个目标 System.Type 要匹配时,则应用另一种路径。

这在以下情况下使用:

  • 调用 DynValue.ToObject 时
  • 使用索引器从表中检索值时
  • 在受限转换的一些特定子情况下(见下文)

这里我们看到默认转换。它实际上很简单:

MoonSharp typeCLR typeNotes
nilnull

Applied to every value which is nil.

翻译:应用于每个值为 nil 的情况。

booleanSystem.Boolean
numberSystem.Double
stringSystem.String
functionMoonSharp.Interpreter.Closure

If DataType is Function.

翻译:如果数据类型是函数(Function)。

functionMoonSharp.Interpreter.CallbackFunction

If DataType is ClrFunction.

翻译:如果数据类型是 CLR 函数(ClrFunction)。

tableMoonSharp.Interpreter.Table
tupleMoonSharp.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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/72898.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ROS云课三分钟-差动移动机器人导航报告如何撰写-及格边缘疯狂试探

提示词&#xff1a;基于如上所有案例并结合roslaunch teb_local_planner_tutorials robot_diff_drive_in_stage.launch和上面所有对话内容&#xff0c;设计一个差速移动机器人仿真实验&#xff0c;并完成报告的全文撰写。 差速移动机器人导航仿真实验报告 一、实验目的 验证 T…

ACE协议学习1

在多核系统或复杂SoC&#xff08;System on Chip&#xff09;中&#xff0c;不同处理器核心或IP&#xff08;Intellectual Property&#xff09;模块之间需要保持数据的一致性。常用的是ACE协议or CHI。 先对ACE协议进行学习 ACE协议&#xff08;Advanced Microcontroller Bu…

ajax之生成一个ajax的demo示例

目录 一. node.js和express ​二. 使用express创建后端服务 三. 创建前端 一. node.js和express ajax是前端在不刷新的情况下访问后端的技术&#xff0c;所以首先需要配置一个后端服务&#xff0c;可以使用node.js和express。 首先生成一个空项目&#xff0c;新建main目录…

Java 字节码操纵框架 -ASM

Java 字节码操纵框架 -ASM 1.ASM 概述: ASM 是用于 Java 字节码操纵的框架,可动态生成新类或增强现有类的功能。它既能直接产生二进制 class 文件,也能在类被加载到虚拟机之前动态改变类行为,通过读取类文件信息来分析、修改类行为,甚至生成新类。许多流行框架如 cglib、…

kafka + flink +mysql 案例

假设你有两个Kafka主题&#xff1a;user_activities_topic 和 product_views_topic&#xff0c;并且你希望将user_activities_topic中的数据写入到user_activities表&#xff0c;而将product_views_topic中的数据写入到product_views表。 maven <dependencies><!-- …

远程登录客户端软件 CTerm 发布了 v4.0.0

有时候我们需要远程登录到 Linux/Unix 服务器&#xff0c;这方面使用最广泛的客户端软件是 PuTTY&#xff0c;不过它是全英文的&#xff0c;而且是单窗口的&#xff0c;有时候显得不那么方便。 CTerm (Clever Terminal) 是一个 Windows 平台下支持 Telnet 和 SSH 协议进行远程…

从李佳琦团队看新型用工:灵活就业如何重构组织架构?

2022年“双11”期间&#xff0c;李佳琦直播间累计销售额突破115亿元&#xff08;来源&#xff1a;新腕数据《2022双11直播电商战报》&#xff09;&#xff0c;其背后团队规模约400人&#xff0c;但全职员工仅占35%&#xff0c;其余65%为外包选品团队、兼职客服、第三方MCN机构人…

微软程序的打包格式MSIX

MSIX 微软推出的MSIX格式是其为统一Windows应用程序打包和部署而设计的新一代安装包格式&#xff0c;具有以下核心特点和进展&#xff1a; 1. 推出背景与时间线 MSIX最初于2018年在微软Build大会上宣布&#xff0c;并在同年7月发布预览版打包工具&#xff0c;10月正式版上线…

AFL++安装

学习fuzzing也几天了&#xff0c;今天记录AFL的安装及使用 一、实验环境 虚拟机&#xff1a;ubuntu20.04 当然也可以uname -a去看自己的版本号 二、AFL安装 1.先更新一下工具 sudo apt update2.安装AFL必要的一些依赖&#xff0c;例如编译工具&#xff08;如 build-essen…

【STM32】ADC功能-单通道多通道(学习笔记)

本章结合上一节内容复习更好理解【江协科技STM32】ADC数模转换器-学习笔记-CSDN博客 一、ADC单通道 接线图 ADC初始化 ①RCC开启时钟&#xff0c;包括ADC和GPIO的时钟&#xff0c;另外ADCCLK的分频器也要配置 ②配置GPIO,&#xff0c;把需要用的GPIO配置成模拟输入模式&am…

基于YOLO11深度学习的运动品牌LOGO检测与识别系统【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

当前主流的大模型训练与推理框架的全面汇总

以下是当前主流的大模型训练与推理框架的全面汇总 以下是更新后包含 SGLang 的大模型训练与推理框架列表&#xff0c;并对分类和示例进行了优化&#xff1a; 一、通用深度学习推理框架 TensorRT-LLM 特点&#xff1a;NVIDIA推出的针对Transformer类模型的优化框架&#xff0c;支…

Linux学习(八)(服务管理(检查服务状态,开始/停止服务,检查服务日志,创建新服务))

服务管理 Linux 中的服务管理是指控制 Linux 在启动和关闭计算机的过程中启动和停止的服务&#xff08;或“守护程序”&#xff09;的系统。这些服务执行各种功能&#xff0c;并提供未附加到用户界面的进程。 Linux 系统&#xff0c;尤其是系统管理员&#xff0c;通常需要管理…

ElasticSearch 分词器介绍及测试:Standard(标准分词器)、English(英文分词器)、Chinese(中文分词器)、IK(IK 分词器)

ElasticSearch 分词器介绍及测试&#xff1a;Standard&#xff08;标准分词器&#xff09;、English&#xff08;英文分词器&#xff09;、Chinese&#xff08;中文分词器&#xff09;、IK&#xff08;IK 分词器&#xff09; ElasticSearch 分词器介绍及测试1. Standard Analyz…

【计算机网络】确认家庭网络是千兆/百兆带宽并排查问题

要确认你的带宽是千兆&#xff08;1000Mbps&#xff09;还是百兆&#xff08;100Mbps&#xff09;&#xff0c;可以通过以下方法逐步排查&#xff1a; 一、检查物理设备 1. 查看路由器和光猫的网口 千兆网口&#xff1a;路由器或光猫的网口旁通常会标注 “10/100/1000M” 或 …

[数据分享第七弹]全球洪水相关数据集

洪水是一种常见的自然灾害&#xff0c;在全球范围内造成了极为严重的威胁。近年来&#xff0c;针对洪水事件的检测分析&#xff0c;以及对于洪水灾害和灾后恢复能力的研究日渐增多&#xff0c;也产生了众多洪水数据集。今天&#xff0c;我们一起来收集整理一下相关数据集。&…

深入探讨AI-Ops架构 第一讲 - 运维的进化历程以及未来发展趋势

首先&#xff0c;让我们一起回顾运维的进化之路&#xff0c;然后再深入探讨AI-Ops架构的细节。 运维的进化历程 1. AI 大范围普及前的运维状态 (传统运维) 在AI技术尚未广泛渗透到运维领域之前&#xff0c;我们称之为传统运维&#xff0c;其主要特点是&#xff1a; 人工驱动…

Hive-数据倾斜优化

数据倾斜的原因 1&#xff09;key分布不均匀&#xff0c;本质上就是业务数据有可能会存在倾斜 2&#xff09;某些SQL语句本身就有数据倾斜 关键词 情形 后果 Join A、其中一个表较小&#xff0c;但是key集中; B、两张表都是大表&#xff0c;key不均 分发到…

番外篇 - Docker的使用

一、Docker的介绍 Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言 并遵从Apache2.0协议开源。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。 容器是完…

深度学习与普通神经网络有何区别?

深度学习与普通神经网络的主要区别体现在以下几个方面&#xff1a; 一、结构复杂度 普通神经网络&#xff1a;通常指浅层结构&#xff0c;层数较少&#xff0c;一般为2-3层&#xff0c;包括输入层、一个或多个隐藏层、输出层。深度学习&#xff1a;强调通过5层以上的深度架构…