免费发布信息网站大全666免费可商用的cms
- 作者: 五速梦信息网
- 时间: 2026年04月20日 10:25
当前位置: 首页 > news >正文
免费发布信息网站大全666,免费可商用的cms,wordpress设置主题404模板,开发区二手房目录 6.Sharing objects 我们先来简单谈谈类型描述符 先说类型描述 稍微复杂一点 调用静态成员 应该使用 “:” 还是 “.” 重载 ByRef 参数#xff08;C# 中的 ref/out#xff09; 索引器 userdata 上的运算符和元方法 扩展方法 事件 关于 InteropAccessMode 的…目录 6.Sharing objects 我们先来简单谈谈类型描述符 先说类型描述 稍微复杂一点 调用静态成员 应该使用 “:” 还是 “.” 重载 ByRef 参数C# 中的 ref/out 索引器 userdata 上的运算符和元方法 扩展方法 事件 关于 InteropAccessMode 的说明 更改可见性使用 MoonSharpHidden 和 MoonSharpVisible 移除成员 官方链接 MoonSharp 6.Sharing objects 让 Lua 和 C# 互相交流。 备注本页面中列出的某些特性反映了主分支的当前状态因此可能有一些特性在最新版本中缺失。 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 typesUserData.RegisterAssembly();Script script new Script();// Pass an instance of MyClass to the script in a globalscript.Globals[obj] new MyClass();DynValue res script.DoString(scriptCode);return res.Number; } 这里我们 • 使用 [MoonSharpUserData] 属性定义了一个类 • 在脚本中将一个 MyClass 对象实例作为全局变量传递 • 从脚本中调用了 MyClass 的一个方法。所有回调的映射规则都适用 稍微复杂一点 让我们尝试一个更复杂的例子。 class MyClass {public double CalcHypotenuse(double a, double b){return Math.Sqrt(a * a b * b);} }static double CallMyClass2() {string scriptCode return obj.calcHypotenuse(3, 4);;// Register just MyClass, explicitely.UserData.RegisterTypeMyClass();Script script new Script();// create a userdata, again, explicitely.DynValue obj UserData.Create(new MyClass());script.Globals.Set(obj, obj);DynValue res script.DoString(scriptCode);return res.Number; } 这里的主要区别在于 • 没有使用 [MoonSharpUserData] 属性。我们不再需要它了。 • 我们调用 RegisterType 来注册一个特定类型而不是使用 RegisterAssembly。 • 我们显式地创建了 userdata DynValue。 • 另外请注意在 C# 代码中方法名为 CalcHypotenuse但在 Lua 脚本中被调用为 calcHypotenuse。 只要其他版本不存在MoonSharp 会以一些有限的方式自动调整大小写以匹配成员以更好地适应不同语言语法约定。例如一个名为 SomeMethodWithLongName 的成员也可以在 Lua 脚本中被访问为 someMethodWithLongName 或 some_method_with_long_name。 调用静态成员 假设我们的类中有一个静态方法 calcHypotenuse。 [MoonSharpUserData] class MyClassStatic {public static double calcHypotenuse(double a, double b){return Math.Sqrt(a * a b * b);} } 我们可以用两种方式调用它。 第一种方式 - 静态方法可以透明地从一个实例中调用 - 无需做任何操作一切都是自动的。 double MyClassStaticThroughInstance() {string scriptCode return obj.calcHypotenuse(3, 4);;// Automatically register all MoonSharpUserData typesUserData.RegisterAssembly();Script script new Script();script.Globals[obj] new MyClassStatic();DynValue res script.DoString(scriptCode);return res.Number; } 另一种方式 - 可以通过直接传递类型或使用 UserData.CreateStatic 方法创建一个占位符用户数据 double MyClassStaticThroughPlaceholder() {string scriptCode return obj.calcHypotenuse(3, 4);;// Automatically register all MoonSharpUserData typesUserData.RegisterAssembly();Script script new Script();script.Globals[obj] typeof(MyClassStatic);DynValue res script.DoString(scriptCode);return res.Number; } 应该使用 “:” 还是 “.” 考虑到上述例子中的代码一个很好的问题是是否应该使用这种语法。 return obj.calcHypotenuse(3, 4); 或者 return obj:calcHypotenuse(3, 4); 99.999% 的情况下这没有任何区别。MoonSharp 知道正在对一个 userdata 进行调用并会相应地处理。 有些极端情况可能会有所不同比如如果一个属性返回一个委托并且你打算立即调用那个委托以原始对象作为实例。这是一个较少见的情景当这种情况发生时你需要手动处理。 重载 重载方法是支持的。重载方法的分派有些神奇不像C#重载分派那样确定。这是因为存在一些歧义。例如一个对象可以声明这两个方法 void DoSomething(int i) { … } void DoSomething(float f) { … } 如何让 MoonSharp 知道在 Lua 中所有数字都是双精度类型的情况下应该调用哪个方法 为解决这个问题MoonSharp 根据输入类型为所有重载计算出一个启发式因子并选择最佳重载。如果你认为 MoonSharp 在解析重载时出现了错误请向论坛或 Discord 报告以便对启发式进行校准。 MoonSharp 尽可能保持启发式权重的稳定性并且在方法之间的得分出现平局时它总是以确定的方式选择相同的一个以提供在不同构建和平台之间一致的体验。 话虽如此MoonSharp 选择的重载可能与你想的不同。因此极其重要的是重载执行等效的任务以便将调用错误重载的影响降到最低。这本应是一个最佳实践但在这里强化这一概念是值得的。 ByRef 参数C# 中的 ref/out ByRef 方法参数通过 MoonSharp 作为多个返回值正确地进行了封送处理。这种支持并非没有副作用因为带有 ByRef 参数的方法无法进行优化。 假设我们有这样一个 C# 方法为了论证起见暴露在一个名为 myobj 的 userdata 中 public string ManipulateString(string input, ref string tobeconcat, out string lowercase) {tobeconcat input tobeconcat;lowercase input.ToLower();return input.ToUpper(); } 我们可以通过以下方式从 Lua 代码调用这个方法并获取结果 x, y, z myobj:manipulateString(CiAo, hello);– x will be CIAO – y will be CiAohello – z will be ciao 虽然支持ByRef 参数会导致方法总是通过反射来调用因此可能会在非 AOT 平台上降低性能AOT 平台本来就慢… 抱怨请向苹果公司反映不要找我。 索引器 C# 允许创建索引器方法。例如 class IndexerTestClass {Dictionaryint, int mymap new Dictionaryint, int();public int this[int idx]{get { return mymap[idx]; }set { mymap[idx] value; }}public int this[int idx1, int idx2, int idx3]{get { int idx (idx1 idx2) * idx3; return mymap[idx]; }set { int idx (idx1 idx2) * idx3; mymap[idx] value; }} } 作为 Lua 语言的扩展MoonSharp 允许在方括号内使用表达式列表来索引用户数据。例如如果 o 是上述类的一个实例那么以下代码行是有效的 – sets the value of an indexer o[5] 19; – use the value of an indexer x 5 o[5]; – sets the value of an indexer using multiple indices (not standard Lua!) o[1,2,3] 19; – use the value of an indexer using multiple indices (not standard Lua!) x 5 o[1,2,3]; 请注意对非用户数据使用多个索引将引发错误。这包括通过元方法的场景但如果元表的 __index 字段设置为用户数据也可以是递归的则支持多重索引。 简而言之这是有效的 m { index o,newindex o }t { }setmetatable(t, m);t[10,11,12] 1234; return t[10,11,12];; 并且这不会 m { – we cant even write meaningful functions here, but lets pretend…__index function(obj, idx) return o[idx] end, __newindex function(obj, idx, val) end }t { }setmetatable(t, m);t[10,11,12] 1234; return t[10,11,12];; userdata 上的运算符和元方法 支持重载运算符。 以下是标准描述符如何分派运算符的说明但你可以在此单元测试代码中看到工作示例。 显式元方法实现 首先如果实现了一个或多个使用 MoonSharpUserDataMetamethod 修饰的静态方法则使用这些方法来分派相应的元方法。请注意如果这些方法存在它们将优先于以下任何其他标准。 pow、concat、call、pairs 和 ipairs 只能通过这种方式实现除非使用自定义描述符。 例如以下代码将实现 concat (..) 运算符 [MoonSharpUserDataMetamethod(concat)] public static int Concat(ArithmOperatorsTestClass o, int v) {return o.Value v; }[MoonSharpUserDataMetamethod(concat)] public static int Concat(int v, ArithmOperatorsTestClass o) {return o.Value v; }[MoonSharpUserDataMetamethod(concat)] public static int Concat(ArithmOperatorsTestClass o1, ArithmOperatorsTestClass o2) {return o1.Value o2.Value; } 隐式元方法实现用于算术运算符 如果找到算术运算符将通过运算符重载自动处理。 public static int operator (ArithmOperatorsTestClass o, int v) {return o.Value v; }public static int operator (int v, ArithmOperatorsTestClass o) {return o.Value v; }public static int operator (ArithmOperatorsTestClass o1, ArithmOperatorsTestClass o2) {return o1.Value o2.Value; } 这将可以在 Lua 脚本中对数字和此对象使用 运算符。 加法、减法、乘法、除法、取模和一元负运算符都以这种方式支持。 比较运算符、长度运算符和 __iterator 元方法 相等运算符 和 ~使用 System.Object.Equals 自动解析。 如果对象实现了 IComparable则使用 IComparable.CompareTo 自动解析比较运算符、 等。 如果对象实现了 Length 或 Count 属性则长度 (#) 运算符将分派到这些属性。 最后如果类实现了 System.Collections.IEnumerable则 __iterator 元方法会自动分派到 GetEnumerator。 扩展方法 支持扩展方法。 扩展方法必须使用 UserData.RegisterExtensionType 或通过 RegisterAssembly(assembly, true) 进行注册。前者将注册一个包含扩展方法的单一类型后者注册指定程序集中包含的所有扩展类型。 扩展方法与其他方法重载一起解析。 事件 也支持事件但方式相当简约。只支持符合以下约束的事件 事件必须在引用类型中声明 事件必须同时实现 add 和 remove 方法 事件处理程序的返回类型必须是 System.Void在 VB.NET 中必须是 Sub 事件处理程序必须有 16 个或更少的参数 事件处理程序不能有值类型参数或按引用传递的参数 事件处理程序签名不能包含指针或未解析的泛型 事件处理程序的所有参数必须可转换为 MoonSharp 类型 这些约束的目的是尽可能避免在运行时构建代码。 虽然它们可能看起来有限制但在大多数情况下它们实际上反映了事件设计中的一些最佳实践它们足以支持 EventHandler 和 EventHandlerT 类型的事件处理程序而这些是目前最常见的前提是至少将 EventArgs 注册为用户数据。 下面是一个使用事件的简单示例 class MyClass {public event EventHandler SomethingHappened;public void RaiseTheEvent(){if (SomethingHappened ! null)SomethingHappened(this, EventArgs.Empty);} }static void Events() {string scriptCode function handler(o, a)print(handled!, o, a);endmyobj.somethingHappened.add(handler);myobj.raiseTheEvent();myobj.somethingHappened.remove(handler);myobj.raiseTheEvent();;UserData.RegisterTypeEventArgs();UserData.RegisterTypeMyClass();Script script new Script();script.Globals[myobj] new MyClass();script.DoString(scriptCode); } 请注意这一次事件是由 Lua 代码触发的,但它也可能由 C# 触发,不会有任何问题。 添加和移除事件处理程序是缓慢的操作,它们是在一个线程锁下使用反射执行的。另一方面,处理事件本身并没有很大的性能损失。 关于 InteropAccessMode 的说明 如果你在 IDE 中输入了所有到目前为止的示例你可能已经注意到大多数方法都有一个可选的 InteropAccessMode 类型参数。 InteropAccessMode 定义了标准描述符如何处理对 CLR 事物的回调。可用的值包括 有一个 UserData.DefaultAccessMode 静态属性用来指定哪个值应被视为默认值当前是 LazyOptimized除非进行更改。 ReflectionOptimization is not performed and reflection is used everytime to access members. This is the slowest approach but saves a lot of memory if members are seldomly used. 翻译没有进行优化每次访问成员时都使用反射。这是最慢的方法但如果很少使用成员则可以节省大量内存。LazyOptimizedThis is a hint, and MoonSharp is free to downgrade this to Reflection. Optimization is done on the fly the first time a member is accessed. This saves memory for all members that are never accessed, at the cost of an increased script execution time. 翻译这是一个提示MoonSharp 可以自由地将其“降级”到反射。第一次访问成员时进行即时优化。这样可以为从未访问过的所有成员节省内存但代价是增加了脚本执行时间。PreoptimizedThis is a hint, and MoonSharp is free to downgrade this to Reflection. Optimization is done in a background thread which starts at registration time. If a member is accessed before optimization is completed, reflection is used. 翻译这是一个提示MoonSharp 可以自由地将其“降级”到反射。优化在注册时开始的后台线程中执行。如果在优化完成之前访问了成员则使用反射。BackgroundOptimizedThis is a hint, and MoonSharp is free to downgrade this to Reflection. Optimization is done at registration time. 翻译这是一个提示,MoonSharp可以自由地将其降级到反射。优化是在注册时完成的。HideMembersMembers are simply not accessible at all. Can be useful if you need a userdata type whose members are hidden from scripts but can still be passed around to other functions. See also AnonWrapper and AnonWrapperT. 翻译成员完全不可访问。如果您需要一个用户数据类型,其成员对脚本是隐藏的,但仍然可以传递给其他函数,这可能很有用。另请参阅AnonWrapper和AnonWrapperT。DefaultUse the default access mode 翻译使用默认的访问模式。 请注意,许多模式 - 特别是 LazyOptimized、Preoptimized 和 BackgroundOptimized - 只是提示,MoonSharp 可以自由地将它们降级为 Reflection。例如,在代码提前编译的平台(如iPhone和iPad)上就会发生这种情况。 更改可见性使用 MoonSharpHidden 和 MoonSharpVisible 可以使用 MoonSharpHidden 和/或 MoonSharpVisible 属性来覆盖成员的默认可见性MoonSharpHidden 是 MoonSharpVisible(false) 的快捷方式。以下是一些带有注释的示例——并不复杂 public class SampleClass {// Not visible - its privateprivate void Method1() { }// Visible - its publicpublic void Method2() { }// Visible - its private but forced visible by attribute[MoonSharpVisible(true)]private void Method3() { }// Not visible - its public but forced hidden by attribute[MoonSharpVisible(false)]public void Method4() { }// Not visible - its public but forced hidden by attribute[MoonSharpHidden]public void Method4() { }// Not visible - its privateprivate int Field1 0;// Visible - its publicpublic int Field2 0;// Visible - its private but forced visible by attribute[MoonSharpVisible(true)]private int Field3 0;// Not visible - its public but forced hidden by attribute[MoonSharpVisible(false)]public int Field4 0;// Not visible at all - its privateprivate int Property1 { get; set; }// Read/write - its publicpublic int Property2 { get; set; }// Readonly - its public, but the setter is privatepublic int Property3 { get; private set; }// Write only! - the MoonSharpVisible makes the getter hidden and the setter visible!public int Property4 { [MoonSharpVisible(false)] get; [MoonSharpVisible(true)] private set; }// Write only! - the MoonSharpVisible makes the whole property hidden but another attribute resets the setter as visible![MoonSharpVisible(false)]public int Property5 { get; [MoonSharpVisible(true)] private set; }// Not visible at all - the MoonSharpVisible hides everything[MoonSharpVisible(false)]public int Property6 { get; set; }// Not visible - its privateprivate event EventHandler Event1;// Visible - its publicpublic event EventHandler Event2;// Visible - its private but forced visible by attribute[MoonSharpVisible(true)]private event EventHandler Event3;// Not visible - its public but forced hidden by attribute[MoonSharpVisible(false)]public event EventHandler Event4;// Not visible - visibility modifiers over add and remove are not currently supported![MoonSharpVisible(false)]public event EventHandler Event5 { [MoonSharpVisible(true)] add { } [MoonSharpVisible(true)] remove { } } } 移除成员 有时需要从已注册的类型中移除成员以便在脚本中隐藏它们。有几种方法可以做到这一点。其中一种方法是在类型注册后手动移除它们 var descr ((StandardUserDataDescriptor)(UserData.RegisterTypeSomeType())); descr.RemoveMember(SomeMember); 或者只需将此属性添加到类型声明中 [MoonSharpHide(SomeMember)] public class SomeType … 这是非常重要的,因为你可能希望隐藏某些你没有重写的继承成员。 end
相关文章
-
免费发布信息不收费的网站100个万能营销方案
免费发布信息不收费的网站100个万能营销方案
- 技术栈
- 2026年04月20日
-
免费发布推广信息佛山债优化
免费发布推广信息佛山债优化
- 技术栈
- 2026年04月20日
-
免费动画制作软件郑州seo招聘
免费动画制作软件郑州seo招聘
- 技术栈
- 2026年04月20日
-
免费发布信息有哪些网站wordpress模板双响
免费发布信息有哪些网站wordpress模板双响
- 技术栈
- 2026年04月20日
-
免费发帖的网站设计上海门票
免费发帖的网站设计上海门票
- 技术栈
- 2026年04月20日
-
免费分类信息网站源码好看的网页源码
免费分类信息网站源码好看的网页源码
- 技术栈
- 2026年04月20日
