向.NET应用程序添加脚本功能

时间:2008-08-01 23:22:09

标签: c# .net scripting compiler-construction

我有一个用C#编写的小游戏。它使用数据库作为后端。它的 一个trading card game,我想将卡的功能实现为脚本。

我的意思是我基​​本上有一个接口ICard,卡类实现(public class Card056: ICard)并且包含游戏调用的函数。

现在,为了使这个东西可维护/可修改,我希望每个卡的类作为数据库中的源代码,并在第一次使用时基本上编译它。因此,当我必须添加/更改卡时,我只需将其添加到数据库并告诉我的应用程序刷新,而无需任何程序集部署(特别是因为我们将讨论每个卡的一个程序集,这意味着数百个程序集)

这可能吗?从源文件注册一个类,然后实例化它等等。

ICard Cards[current] = new MyGame.CardLibrary.Card056();
Cards[current].OnEnterPlay(ref currentGameState);

语言是C#,但如果可以用任何.NET语言编写脚本,则可获得额外奖励。

9 个答案:

答案 0 :(得分:39)

Oleg Shilo's C# Script solution (at The Code Project)真的是在您的应用程序中提供脚本功能的一个很好的介绍。

另一种方法是考虑专门为脚本编写的语言,例如IronRubyIronPythonLua

IronPython和IronRuby今天都可以使用。

有关嵌入IronPython的指南,请参阅 How to embed IronPython script support in your existing app in 10 easy steps

Lua是一种常用于游戏的脚本语言。有一个用于.NET的Lua编译器,可从CodePlex获得 - http://www.codeplex.com/Nua

如果您想了解如何在.NET中构建编译器,那么该代码库是一个很好的阅读。

完全不同的角度是尝试PowerShell。有许多将PowerShell嵌入到应用程序中的示例 - 这是关于该主题的完整项目: Powershell Tunnel

答案 1 :(得分:7)

您可能可以使用IronRuby。

否则我建议你有一个放置预编译程序集的目录。然后,您可以在DB中为程序集和类提供引用,并使用反射在运行时加载正确的程序集。

如果你真的想在运行时编译你可以使用CodeDOM,那么你可以使用反射来加载动态程序集。 Microsoft documentation article which might help

答案 2 :(得分:6)

如果您不想使用DLR,可以use Boo (which has an interpreter)或者考虑the Script.NET (S#) project on CodePlex。使用Boo解决方案,您可以在编译脚本之间进行选择或使用解释器,Boo通过其开放式编译器架构提供了一种很好的脚本语言,具有灵活的语法和可扩展的语言。但是,Script.NET看起来也不错,你可以轻松地扩展该语言以及它的开源项目,并使用非常友好的编译器生成器(Irony.net)。

答案 3 :(得分:5)

您可以使用任何DLR语言,它们提供了一种非常容易托管您自己的脚本平台的方法。但是,您不必使用脚本语言。您可以使用C#并使用C#代码提供程序对其进行编译。只要您将其加载到自己的AppDomain中,就可以加载和卸载它的内容。

答案 4 :(得分:5)

我建议使用LuaInterface,因为它已经完全实现了Lua,看起来Nua不完整,可能没有实现一些非常有用的功能(协同程序等)。

如果你想使用一些外部预先打包的Lua模块,我建议使用1.5.x的内容,而不是构建完全托管代码的2.x系列,并且不能公开必要的C API。

答案 5 :(得分:5)

我正在使用LuaInterface1.3 + Lua 5.0作为.NET 1.1应用程序。

Boo的问题在于,每次你动态解析/编译/评估你的代码时,它会创建一组boo类,这样你就会出现内存泄漏。

另一方面,Lua不这样做,所以它非常稳定并且工作得非常好(我可以将对象从C#传递给Lua并向后传递)。

到目前为止,我还没有把它放在PROD中,但看起来很有希望。

我在使用LuaInterface + Lua 5.0 的PROD中确实存在内存泄漏问题,因此我使用了Lua 5.2并直接链接到带有DllImport的C#。 内存泄漏位于LuaInterface库中。

Lua 5.2:来自http://luabinaries.sourceforge.nethttp://sourceforge.net/projects/luabinaries/files/5.2/Windows%20Libraries/Dynamic/lua-5.2_Win32_dll7_lib.zip/download

一旦我这样做,我的所有内存泄漏都消失了,应用程序非常稳定。

答案 6 :(得分:4)

是的,我考虑过这一点,但很快我发现另一个特定于域的语言(DSL)会有点过分。

基本上,他们需要以可能无法预测的方式与我的游戏状态进行交互。例如,一张牌可以有一条规则“当这张牌进入游戏时,你的所有亡灵爪牙都会对飞行的敌人获得+3攻击,除非敌人受到祝福”。由于交易卡游戏是基于交易的,GameState Manager将触发OnStageX事件并让卡以任何方式修改其他卡或GameState。

如果我尝试创建DSL,我必须实现一个相当大的功能集,并可能不断更新它,这会将维护工作转移到另一个部分,而不会实际删除它。

这就是为什么我想继续使用“真正的”.NET语言来基本上只能触发事件并让卡以任何方式操纵游戏状态(在代码访问安全性的限制范围内)。

答案 7 :(得分:4)

我的部门销售的主要应用程序非常类似于提供客户端自定义(这意味着我无法发布任何来源)。我们有一个加载动态VB.NET脚本的C#应用​​程序(尽管可以轻松支持任何.NET语言 - 选择VB是因为定制团队来自ASP背景。)

使用.NET的CodeDom,我们使用VB CodeDomProvider从数据库编译脚本(如果你想支持使用“CompilerVersion”传递字典所需的3.5功能,那么它很可能默认为.NET 2) “v3.5”到它的构造函数)。使用CodeDomProvider.CompileAssemblyFromSource方法编译它(您可以传递设置以强制它仅在内存中编译。

这会导致内存中有数百个程序集,但您可以将所有动态类的代码放在一个程序集中,并在任何更改时重新编译整个程序集。这样做的好处是,您可以在测试时添加一个标记以在PDB的磁盘上进行编译,从而允许您通过动态代码进行调试。

答案 8 :(得分:3)

.NET的下一个版本(5.0?)已经有很多关于打开“编译器即服务”的讨论,这可能会使直接脚本评估成为可能。