C# 向 .NET 应用程序添加脚本功能
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/260/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Adding scripting functionality to .NET applications
提问by Michael Stum
I have a little game written in C#. It uses a database as back-end. It's a trading card game, and I wanted to implement the function of the cards as a script.
我有一个用 C# 编写的小游戏。它使用数据库作为后端。这是一个集换式卡牌游戏,我想将卡牌的功能作为脚本来实现。
What I mean is that I essentially have an interface, ICard
, which a card class implements (public class Card056: ICard
) and which contains a function that is called by the game.
我的意思是我本质上有一个接口, ICard
, 卡类实现 ( public class Card056: ICard
) 并包含一个由游戏调用的函数。
Now, to make the thing maintainable/moddable, I would like to have the class for each card as source code in the database and essentially compile it on first use. So when I have to add/change a card, I'll just add it to the database and tell my application to refresh, without needing any assembly deployment (especially since we would be talking about 1 assembly per card which means hundreds of assemblies).
现在,为了使事情可维护/可修改,我希望将每张卡的类作为数据库中的源代码,并在首次使用时对其进行编译。因此,当我必须添加/更改卡片时,我只需将其添加到数据库并告诉我的应用程序进行刷新,而无需任何程序集部署(特别是因为我们将讨论每张卡 1 个程序集,这意味着数百个程序集) .
Is that possible? Register a class from a source file and then instantiate it, etc.
那可能吗?从源文件注册一个类,然后实例化它,等等。
ICard Cards[current] = new MyGame.CardLibrary.Card056();
Cards[current].OnEnterPlay(ref currentGameState);
The language is C# but extra bonus if it's possible to write the script in any .NET language.
语言是 C#,但如果可以用任何 .NET 语言编写脚本,则额外奖励。
采纳答案by Leon Bambrick
Oleg Shilo's C# Script solution (at The Code Project) really is a great introduction to providing script abilities in your application.
Oleg Shilo 的 C# Script 解决方案(在 The Code Project 中)确实很好地介绍了在您的应用程序中提供脚本功能。
A different approach would be to consider a language that is specifically built for scripting, such as IronRuby, IronPython, or Lua.
另一种方法是考虑专门为脚本编写的语言,例如IronRuby、IronPython或Lua。
IronPython and IronRuby are both available today.
IronPython 和 IronRuby 现已上市。
For a guide to embedding IronPython read How to embed IronPython script support in your existing app in 10 easy steps.
有关嵌入 IronPython 的指南,请阅读 如何通过 10 个简单步骤在现有应用程序中嵌入 IronPython 脚本支持。
Lua is a scripting language commonly used in games. There is a Lua compiler for .NET, available from CodePlex -- http://www.codeplex.com/Nua
Lua 是一种游戏中常用的脚本语言。有一个用于 .NET 的 Lua 编译器,可从 CodePlex 获得——http: //www.codeplex.com/Nua
That codebase is a great read if you want to learn about building a compiler in .NET.
如果您想了解如何在 .NET 中构建编译器,那么该代码库非常适合阅读。
A different angle altogether is to try PowerShell. There are numerous examples of embedding PowerShell into an application -- here's a thorough project on the topic: Powershell Tunnel
完全不同的角度是尝试PowerShell。有许多将 PowerShell 嵌入应用程序的示例——这里有一个关于该主题的完整项目: Powershell Tunnel
回答by Michael Stum
Yes, I thought about that, but I soon figured out that another Domain-Specific-Language (DSL) would be a bit too much.
是的,我考虑过这一点,但我很快发现另一种领域特定语言 (DSL) 有点过分了。
Essentially, they need to interact with my gamestate in possibly unpredictable ways. For example, a card could have a rule "When this cards enter play, all your undead minions gain +3 attack against flying enemies, except when the enemy is blessed". As trading card games are turn based, the GameState Manager will fire OnStageX events and let the cards modify other cards or the GameState in whatever way the card needs.
本质上,他们需要以可能无法预测的方式与我的游戏状态进行交互。例如,一张牌可以有一个规则“当这张牌进场时,你的所有不死随从对飞行敌人的攻击力+3,除非敌人受到祝福”。由于集换式卡牌游戏是回合制的,GameState 管理器将触发 OnStageX 事件,让卡牌以卡牌需要的任何方式修改其他卡牌或 GameState。
If I try to create a DSL, I have to implement a rather large feature set and possibly constantly update it, which shifts the maintenance work to another part without actually removing it.
如果我尝试创建一个 DSL,我必须实现一个相当大的功能集并可能不断更新它,这会将维护工作转移到另一个部分,而无需实际删除它。
That's why I wanted to stay with a "real" .NET language to essentially be able to just fire the event and let the card manipulate the gamestate in whatever way (within the limits of the code access security).
这就是为什么我想使用“真正的”.NET 语言,以便基本上能够触发事件并让卡片以任何方式(在代码访问安全性的限制内)操纵游戏状态。
回答by Eric Haskins
You might be able to use IronRuby for that.
您也许可以使用 IronRuby。
Otherwise I'd suggest you have a directory where you place precompiled assemblies. Then you could have a reference in the DB to the assembly and class, and use reflection to load the proper assemblies at runtime.
否则,我建议您有一个放置预编译程序集的目录。然后,您可以在 DB 中引用程序集和类,并在运行时使用反射加载正确的程序集。
If you really want to compile at run-time you could use the CodeDOM, then you could use reflection to load the dynamic assembly. Microsoft documentation article which might help.
如果你真的想在运行时编译你可以使用 CodeDOM,那么你可以使用反射来加载动态程序集。可能有帮助的 Microsoft 文档文章。
回答by Jesse Ezell
You could use any of the DLR languages, which provide a way to really easily host your own scripting platform. However, you don't have to use a scripting language for this. You could use C# and compile it with the C# code provider. As long as you load it in its own AppDomain, you can load and unload it to your heart's content.
您可以使用任何 DLR 语言,它们提供了一种真正轻松托管您自己的脚本平台的方法。但是,您不必为此使用脚本语言。您可以使用 C# 并使用 C# 代码提供程序编译它。只要你在它自己的AppDomain中加载它,你就可以随心所欲地加载和卸载它。
回答by Nathan
If you don't want to use the DLR you can use Boo (which has an interpreter)or you could consider the Script.NET (S#) project on CodePlex. With the Boo solution you can choose between compiled scripts or using the interpreter, and Boo makes a nice scripting language, has a flexible syntax and an extensible language via its open compiler architecture. Script.NET looks nice too, though, and you could easily extend that language as well as its an open source project and uses a very friendly Compiler Generator (Irony.net).
如果您不想使用 DLR,您可以使用 Boo(它有一个解释器),或者您可以考虑CodePlex 上的 Script.NET (S#) 项目。使用 Boo 解决方案,您可以在编译脚本或使用解释器之间进行选择,Boo 是一种很好的脚本语言,通过其开放的编译器架构具有灵活的语法和可扩展的语言。不过,Script.NET 看起来也不错,您可以轻松扩展该语言及其开源项目,并使用非常友好的编译器生成器 ( Irony.net)。
回答by Keith
The main application that my division sells does something very similar to provide client customisations (which means that I can't post any source). We have a C# application that loads dynamic VB.NET scripts (although any .NET language could be easily supported - VB was chosen because the customisation team came from an ASP background).
我的部门销售的主要应用程序与提供客户定制非常相似(这意味着我不能发布任何来源)。我们有一个加载动态 VB.NET 脚本的 C# 应用程序(尽管可以轻松支持任何 .NET 语言 - 之所以选择 VB,是因为定制团队来自 ASP 背景)。
Using .NET's CodeDom we compile the scripts from the database, using the VB CodeDomProvider
(annoyingly it defaults to .NET 2, if you want to support 3.5 features you need to pass a dictionary with "CompilerVersion" = "v3.5" to its constructor). Use the CodeDomProvider.CompileAssemblyFromSource
method to compile it (you can pass settings to force it to compile in memory only.
使用 .NET 的 CodeDom,我们从数据库中编译脚本,使用 VB CodeDomProvider
(令人讨厌的是它默认为 .NET 2,如果您想支持 3.5 功能,您需要将带有 "CompilerVersion" = "v3.5" 的字典传递给其构造函数)。使用CodeDomProvider.CompileAssemblyFromSource
方法编译它(你可以通过设置来强制它只在内存中编译。
This would result in hundreds of assemblies in memory, but you could put all the dynamic classes' code together into a single assembly, and recompile the whole lot when any change. This has the advantage that you could add a flag to compile on disk with a PDBfor when you're testing, allowing you to debug through the dynamic code.
这将导致内存中有数百个程序集,但您可以将所有动态类的代码放在一个程序集中,并在发生任何更改时重新编译整个程序集。这样做的好处是,您可以添加一个标志,以便在测试时使用PDB在磁盘上进行编译,从而允许您通过动态代码进行调试。
回答by harningt
I'd suggest using LuaInterfaceas it has fully implemented Lua where it appears that Nua is not complete and likely does not implement some very useful functionality (coroutines, etc).
我建议使用LuaInterface,因为它已经完全实现了 Lua,而 Nua 似乎并不完整,并且可能没有实现一些非常有用的功能(协程等)。
If you want to use some of the outside prepacked Lua modules, I'd suggest using something along the lines of 1.5.x as opposed to the 2.x series that builds fully managed code and cannot expose the necessary C API.
如果您想使用一些外部预打包的 Lua 模块,我建议您使用 1.5.x 的内容,而不是构建完全托管代码且无法公开必要的 C API 的 2.x 系列。
回答by Eric Falsken
The next version of .NET (5.0?) has had a lot of talk about opening the "compiler as a service" which would make things like direct script evaluation possible.
.NET 的下一个版本(5.0?)已经有很多关于开放“编译器即服务”的讨论,这将使直接脚本评估之类的事情成为可能。
回答by Kat Lim Ruiz
I'm using LuaInterface1.3 + Lua 5.0 for a NET 1.1 application.
我将 LuaInterface1.3 + Lua 5.0 用于 NET 1.1 应用程序。
The issue with Boo is that every time you parse/compile/eval your code on the fly, it creates a set of boo classes so you will get memory leaks.
Boo 的问题在于,每次您动态解析/编译/评估代码时,它都会创建一组 boo 类,因此您将获得内存泄漏。
Lua in the other hand, does not do that, so it's very very stable and works wonderful (I can pass objects from C# to Lua and backwards).
另一方面,Lua 不这样做,因此它非常稳定并且运行良好(我可以将对象从 C# 传递到 Lua 并反向传递)。
So far I haven't put it in PROD yet, but seems very promising.
到目前为止,我还没有把它放在 PROD 中,但看起来很有希望。
I did have memory leaks issues in PROD using LuaInterface + Lua 5.0, therefore I used Lua 5.2 and linked directly into C# with DllImport. The memory leaks were inside the LuaInterface library.
我确实在使用 LuaInterface + Lua 5.0 的 PROD 中遇到了内存泄漏问题,因此我使用了 Lua 5.2 并通过 DllImport 直接链接到 C#。内存泄漏发生在 LuaInterface 库中。
Lua 5.2: from http://luabinaries.sourceforge.netand http://sourceforge.net/projects/luabinaries/files/5.2/Windows%20Libraries/Dynamic/lua-5.2_Win32_dll7_lib.zip/download
Lua 5.2:来自http://luabinaries.sourceforge.net和http://sourceforge.net/projects/luabinaries/files/5.2/Windows%20Libraries/Dynamic/lua-5.2_Win32_dll7_lib.zip/download
Once I did this, all my memory leaks were gone and the application was very stable.
一旦我这样做了,我所有的内存泄漏都消失了,应用程序非常稳定。