C#デスクトップアプリケーションに埋め込むのに最適なスクリプト言語は何ですか?[閉まっている]


98

複雑でリッチなデスクトップアプリケーションを作成していて、レポート形式に柔軟性を提供する必要があるため、オブジェクトモデルをスクリプト言語に公開するだけだと考えました。それはVBA(これはまだオプションです)を意味する時期でしたが、マネージコードの派生VSTA(私は思う)は衰退しているようです。

Windows .NETの組み込みスクリプト言語に最適な選択肢は何ですか?


FWIW、@ GrantPeterの回答のアプローチから始め、アンロードを許可するためにAppDomainを使用し、クロスドメインオブジェクトリースの更新を処理し、サンドボックスセキュリティ対策をいじっていました。コンパイルされたスクリプトは、AppDomain境界を越えてメインプログラムのメソッドを呼び出すことができます。実験はここで見つけることができます:github.com/fadden/DynamicScriptSandbox
fadden

回答:


24

私はCSScriptを使用して素晴らしい結果を得ました。スクリプト可能なアプリでバインディングやその他の低レベルのことを行う必要が本当に減りました。


1
私は1年以上CS-Scriptを本番環境で使用しており、非常に優れたパフォーマンスを発揮しています。
David Robbins

ところで-C#スクリプトサポートを有効にするには、C#スクリプトライブラリを内部に統合するか、独自にC#スクリプトをコンパイルします。私はここの自分のプロジェクトに同様の軽量のC#スクリプトコンパイラを実行しました: sourceforge.net/p/syncproj/code/HEAD/tree/CsScript.cs C#スクリプトのコンパイル自体は(たとえば、.Luaと比較して)少し遅いです。不要な場合は、余分なコンパイル手順を回避する意味があります。
TarmoPikaro

114

個人的には、スクリプト言語としてC#を使用します。.NETフレームワーク(およびMonoのおかげで、Matthew Scharley氏)は、実際には、フレームワーク自体に各.NET言語のコンパイラーを組み込んでいます。

基本的に、このシステムの実装には2つの部分があります。

  1. ユーザーがコードをコンパイルできるようにするこれは比較的簡単で、数行のコードでのみ実行できます(エラーダイアログを追加することもできますが、これは、使用方法に応じて、おそらく数十行のコードになります)あなたはそれがなりたいです)。

  2. コンパイルされたアセンブリ内に含まれるクラスを作成して使用するこれは、前のステップより少し難しいです(少しのリフレクションが必要です)。基本的には、コンパイルされたアセンブリをプログラムの「プラグイン」として扱うだけです。C#でプラグインシステムを作成するさまざまな方法に関するチュートリアルがかなりあります(Googleはあなたの友達です)。

このシステムを実装する方法を示す「クイック」アプリケーションを実装しました(2つの作業スクリプトが含まれています!)。これはアプリケーションの完全なコードです。新しいコードを作成し、「program.cs」ファイルにコードを貼り付けてください。この時点で、貼り付けようとしているコードの大きなチャンクについて謝罪する必要があります(コードをそれほど大きくするつもりはありませんでしたが、コメントに少し夢中になりました)


using System;
using System.Windows.Forms;
using System.Reflection;
using System.CodeDom.Compiler;

namespace ScriptingInterface
{
    public interface IScriptType1
    {
        string RunScript(int value);
    }
}

namespace ScriptingExample
{
    static class Program
    {
        /// 
        /// The main entry point for the application.
        /// 
        [STAThread]
        static void Main()
        {

            // Lets compile some code (I'm lazy, so I'll just hardcode it all, i'm sure you can work out how to read from a file/text box instead
            Assembly compiledScript = CompileCode(
                "namespace SimpleScripts" +
                "{" +
                "    public class MyScriptMul5 : ScriptingInterface.IScriptType1" +
                "    {" +
                "        public string RunScript(int value)" +
                "        {" +
                "            return this.ToString() + \" just ran! Result: \" + (value*5).ToString();" +
                "        }" +
                "    }" +
                "    public class MyScriptNegate : ScriptingInterface.IScriptType1" +
                "    {" +
                "        public string RunScript(int value)" +
                "        {" +
                "            return this.ToString() + \" just ran! Result: \" + (-value).ToString();" +
                "        }" +
                "    }" +
                "}");

            if (compiledScript != null)
            {
                RunScript(compiledScript);
            }
        }

        static Assembly CompileCode(string code)
        {
            // Create a code provider
            // This class implements the 'CodeDomProvider' class as its base. All of the current .Net languages (at least Microsoft ones)
            // come with thier own implemtation, thus you can allow the user to use the language of thier choice (though i recommend that
            // you don't allow the use of c++, which is too volatile for scripting use - memory leaks anyone?)
            Microsoft.CSharp.CSharpCodeProvider csProvider = new Microsoft.CSharp.CSharpCodeProvider();

            // Setup our options
            CompilerParameters options = new CompilerParameters();
            options.GenerateExecutable = false; // we want a Dll (or "Class Library" as its called in .Net)
            options.GenerateInMemory = true; // Saves us from deleting the Dll when we are done with it, though you could set this to false and save start-up time by next time by not having to re-compile
            // And set any others you want, there a quite a few, take some time to look through them all and decide which fit your application best!

            // Add any references you want the users to be able to access, be warned that giving them access to some classes can allow
            // harmful code to be written and executed. I recommend that you write your own Class library that is the only reference it allows
            // thus they can only do the things you want them to.
            // (though things like "System.Xml.dll" can be useful, just need to provide a way users can read a file to pass in to it)
            // Just to avoid bloatin this example to much, we will just add THIS program to its references, that way we don't need another
            // project to store the interfaces that both this class and the other uses. Just remember, this will expose ALL public classes to
            // the "script"
            options.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);

            // Compile our code
            CompilerResults result;
            result = csProvider.CompileAssemblyFromSource(options, code);

            if (result.Errors.HasErrors)
            {
                // TODO: report back to the user that the script has errored
                return null;
            }

            if (result.Errors.HasWarnings)
            {
                // TODO: tell the user about the warnings, might want to prompt them if they want to continue
                // runnning the "script"
            }

            return result.CompiledAssembly;
        }

        static void RunScript(Assembly script)
        {
            // Now that we have a compiled script, lets run them
            foreach (Type type in script.GetExportedTypes())
            {
                foreach (Type iface in type.GetInterfaces())
                {
                    if (iface == typeof(ScriptingInterface.IScriptType1))
                    {
                        // yay, we found a script interface, lets create it and run it!

                        // Get the constructor for the current type
                        // you can also specify what creation parameter types you want to pass to it,
                        // so you could possibly pass in data it might need, or a class that it can use to query the host application
                        ConstructorInfo constructor = type.GetConstructor(System.Type.EmptyTypes);
                        if (constructor != null && constructor.IsPublic)
                        {
                            // lets be friendly and only do things legitimitely by only using valid constructors

                            // we specified that we wanted a constructor that doesn't take parameters, so don't pass parameters
                            ScriptingInterface.IScriptType1 scriptObject = constructor.Invoke(null) as ScriptingInterface.IScriptType1;
                            if (scriptObject != null)
                            {
                                //Lets run our script and display its results
                                MessageBox.Show(scriptObject.RunScript(50));
                            }
                            else
                            {
                                // hmmm, for some reason it didn't create the object
                                // this shouldn't happen, as we have been doing checks all along, but we should
                                // inform the user something bad has happened, and possibly request them to send
                                // you the script so you can debug this problem
                            }
                        }
                        else
                        {
                            // and even more friendly and explain that there was no valid constructor
                            // found and thats why this script object wasn't run
                        }
                    }
                }
            }
        }
    }
}


2
これがMonoでも機能するのか、それとも.NETでのみ利用できるのか知っていますか?
マシューシャーリー2009年

4
参考までに、そして好奇心のある他の誰にとっても、そうです、これはコンパイルしてMonoでうまく動作します。コンパイル部分にはSystemリファレンスのみが必要です。
マシューシャーリー2009年

3
これを行うと、AppDomainが汚染されます
Daniel Little

4
@Lavinski AppDomainを汚染したくない場合は、新しいものを作成するだけです(おそらく「スクリプト」により厳しいセキュリティを設定できるように、これはおそらく良いアイデアです)
Grant Peters

3
@Lander-これは非常に軽量です。上記のコードは、「スクリプト」をサポートするプログラム全体です。csscript.netこれはある種のラッパーのようです。これは基本的に最小限の実装です。より良い質問は、「csscript.netがこれに対して何をしないのか」ということだと思います。私はcsscriptが何をしているのかわかりませんが、上記のコードが何をしているのかははっきりとわかっています。
グラントピーターズ


19

PowerShellエンジンは、アプリケーションに簡単に埋め込んでスクリプト化できるように設計されています。実際、PowerShell CLIはエンジンへのテキストベースのインターフェイスにすぎません。

編集:https : //devblogs.microsoft.com/powershell/making-applications-scriptable-via-powershell/を参照してください


AppDomainにオブジェクトを追加しないため、これが最良のソリューションだと思います。.Netでは、アセンブリまたはクラスをアンロードすることはできません。
ダニエル・リトル


8

最近のスクリプト言語はLuaです。小さく、高速で、クリーンで、完全に文書化され、十分にサポートされており、優れたコミュニティがあり、業界の多くの大企業(Adobe、Blizzard、EA Games)で使用されており、試してみる価値があります。

.NET言語で使用するには、LuaInterfaceプロジェクトが必要なすべてを提供します。


1
LuaはGarry's Modでのスクリプト作成にも使用されます。これは素晴らしいゲームです:)
匿名の臆病者



2

IronPythonへの別の投票。それを埋め込むのは簡単で、.Netクラスとの相互運用は簡単です。まあ、それはPythonです。


1

私が現在維持しているS#を提案するかもしれません。これは、C#で記述され、.NETアプリケーション用に設計されたオープンソースプロジェクトです。

最初は(2007-2009)http://www.codeplex.com/scriptdotnetでホストされていましたが、最近githubに移動されました。


回答を投稿していただきありがとうございます。セルフプロモーションに関するFAQをよくお読みください。また、独自のサイト/製品にリンクするたびに免責事項を投稿する必要があることにも注意してください。
Andrew Barber、

アンドリューにアドバイスをありがとう。以前の回答の1つに、このスクリプト言語への古いリンクが含まれています。何らかの理由で元の回答にコメントを追加できないため、正しいリンクを提供するために新しい回答を投稿しました。
ピーター



0

クライアント用のプラグインを作成したところ、OfficeのVBAのように機能するモジュールでC#コードを記述できるようになりました。



0

C#自体を使用したスクリプト記述が好きです。現在、2013年には、C#スクリプトのサポートがかなり充実し、そのためのライブラリがますます利用可能になっています。

MonoはC#コードのスクリプト作成に優れたサポートMono.CSharp.dllがあり、アプリケーションにを含めるだけで.NETで使用できます。私が作成したC#スクリプトアプリケーションについては、CShellを確認してください。

また、MicrosoftのRoslynにある「ScriptEngine」も確認してください。ただし、これはCTPのみです。

一部の人々がすでに述べたように、CS-Scriptもかなり以前から存在しています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.