MoonSharp 文档二
目录
6.Sharing objects(共享对象)
我们先来简单谈谈类型描述符
先说类型描述
稍微复杂一点
调用静态成员
应该使用 “:” 还是 “.”
重载
ByRef 参数(C# 中的 ref/out)
索引器
userdata 上的运算符和元方法
扩展方法
事件
关于 InteropAccessMode 的说明
更改可见性:使用 MoonSharpHidden 和 MoonSharpVisible
移除成员
MoonSharp 文档一-CSDN博客
MoonSharp 文档三-CSDN博客
MoonSharp 文档四-CSDN博客
MoonSharp 文档五-CSDN博客
6.Sharing objects(共享对象)
让 Lua 和 C# 互相交流。
文档地址:MoonSharp
备注:本页面中列出的某些特性反映了主分支的当前状态(因此,可能有一些特性在最新版本中缺失)。
MoonSharp 的一个方便特性是能够与脚本共享.NET对象。
默认情况下,一个类型会将其所有的公共方法、公共属性、公共事件和公共字段与Lua脚本共享。可以使用 MoonSharpVisible 特性来覆盖这个默认可见性。
建议使用专用对象作为 CLR 代码和脚本代码之间的接口(而不是将应用程序内部模型暴露给脚本)。许多设计模式(适配器、外观、代理等)可以帮助设计这样一个接口层。这对于以下方面尤其重要:
• 限制脚本可以做什么和不可以做什么(安全性!你想让你的模组作者找到一种方法来删除最终用户的个人文件吗?)
• 为脚本作者提供一个有意义的接口
• 分别记录接口
• 允许内部逻辑和模型在不破坏脚本的情况下进行更改
由于这些原因,MoonSharp 默认需要明确注册将提供给脚本的类型。
如果你处于脚本可以被信任的场景,你可以使用 UserData.RegistrationPolicy = InteropRegistrationPolicy.Automatic; 全局启用自动注册。这很危险,你已经被警告过了。
那么,让我们看看菜单上有什么:
• 首先让我们谈谈类型描述符] - 解释幕后发生的事情以及如何覆盖整个互操作系统的一点理论
• 保持简单 - 入门的最简单方法
• 稍微复杂一点 - 我们深入研究,增加一点复杂性和细节
• 调用静态成员 - 如何调用静态成员
• 应该使用':'还是'.'? - 关于如何调用方法的简单问题
• 重载 - 如何处理重载
• ByRef 参数(C# 中的 ref/out) - 如何处理 ref/out 参数
• 索引器 - 如何处理索引器
• userdata 上的运算符和元方法 - 如何重载运算符等
• 扩展方法 - 如何使用扩展方法
• 事件 - 如何使用事件
• 互操作访问模式 - 什么是互操作访问模式以及它如何工作
• 使用 MoonSharpHidden 和 MoonSharpVisible 更改可见性 - 如何覆盖成员的可见性
• 删除成员 - 如何删除成员的可见性
很多内容,让我们开始吧。
我们先来简单谈谈类型描述符
首先是一些关于互操作如何实现的小理论。每个 CLR 类型都被包装到一个"类型描述符"中,它的作用是向脚本描述 CLR 类型。为互操作注册一个类型意味着将类型与描述符(MoonSharp 可以自己创建)关联起来,描述符将用于调度方法、属性等。
从下一节开始,我们将参考 MoonSharp 提供的"自动"描述符,但你可以实现自己的描述符来提高速度、添加功能、增强安全性等。
如果你想实现自己的描述符(这并不容易,除非你需要,否则不应该这样做),你可以遵循以下路径:
• 创建一个特定的 IUserDataDescriptor 来描述你自己的类型 - 这是最困难的方式。
• 让你的类型实现 IUserDataType 接口。这更容易,但意味着你无法在没有对象实例的情况下处理静态成员。
• 扩展或嵌入 StandardUserDataDescriptor,并在保持其余行为的同时更改你需要的方面。
为了帮助创建描述符,提供了以下类:
• StandardUserDataDescriptor - 这是 MoonSharp 实现的类型描述符 •
• StandardUserDataMethodDescriptor - 这是单个方法/函数的描述符。
• StandardUserDataOverloadedMethodDescriptor - 这是重载和/或扩展方法的描述符。
• StandardUserDataPropertyDescriptor - 这是单个属性的描述符。
• StandardUserDataFieldDescriptor - 这是单个字段的描述符。
关于将值类型作为 userdata 进行互操作的一个小注意事项。
就像调用函数时将值类型作为参数传递一样,脚本将对用户数据的副本进行操作,因此,例如更改用户数据中的字段不会反映在原始值上。同样,这与值类型的标准行为没有任何不同,但足以让人感到惊讶。
此外,值类型不支持引用类型所具有的全部优化范围,因此某些操作在值类型上可能比在引用类型上更慢。
先说类型描述
好的,来看第一个例子。
[MoonSharpUserData]
class MyClass
{
public double calcHypotenuse(double a, double b)
{
return Math.Sqrt(a * a + b * b);
}
}
double CallMyClass1()
{
string scriptCode = @"
return obj.calcHypotenuse(3, 4);
";
// Automatically register all MoonSharpUserData types
UserData.RegisterAssembly();
Script script = new Script();
// Pass an instance of MyClass to the script in a global
script.Globals["obj"] = new MyClass();
DynValue res = script.DoString(scriptCode);
return res.Number;
}
这里我们:
• 使用 [MoonSharpUserData] 属性定义了一个类
• 在脚本中将一个 MyClass 对象实例作为全局变量传递
• 从脚本中调用了 MyClass 的一个方法。所有回调的映射规则都适用
稍微复杂一点
让我们尝试一个更复杂的例子。
class MyClass
{
public do