C # 데스크톱 애플리케이션에 포함하는 데 가장 적합한 스크립팅 언어는 무엇입니까? [닫은]


98

우리는 복잡하고 풍부한 데스크톱 애플리케이션을 작성하고 있으며보고 형식에 유연성을 제공해야하므로 개체 모델을 스크립팅 언어에 노출시킬 것이라고 생각했습니다. 시간은 VBA (여전히 옵션 임)를 의미했지만 관리 코드 파생 VSTA (내 생각에)는 포도 나무에서 시들해진 것 같습니다.

이제 Windows .NET에서 임베디드 스크립팅 언어에 가장 적합한 선택은 무엇입니까?


FWIW, 나는 @GrantPeter의 답변에서 접근 방식으로 시작하고 AppDomain을 사용하여 언로드를 허용하고 교차 도메인 개체 임대 갱신을 처리하고 샌드 박스 보안 조치를 취했습니다. 컴파일 된 스크립트는 AppDomain 경계를 넘어 다시 기본 프로그램의 메서드를 호출 할 수 있습니다. 실험은 여기에서 찾을 수 있습니다. github.com/fadden/DynamicScriptSandbox
fadden

답변:


24

놀라운 결과로 CSScript 를 사용 했습니다 . 스크립팅 가능한 앱에서 바인딩 및 기타 낮은 수준의 작업을 수행해야하는 작업을 정말로 줄여줍니다.


1
저는 1 년 넘게 프로덕션에서 CS-Script를 사용해 왔으며 정말 잘 수행되었습니다.
David Robbins

Btw-C # 스크립트 지원을 사용하려면 C # 스크립트 라이브러리를 내부에 통합하거나 직접 C # 스크립트 컴파일을 수행 할 수 있습니다. 나는 여기에 내 자신의 프로젝트에 유사한 경량의 C # 스크립트 컴파일러를했을 : sourceforge.net/p/syncproj/code/HEAD/tree/CsScript.cs C # 스크립트 컴파일 자체가 (.Lua에 비교 예를 들어보다) 느린 비트이며, 차종을 필요하지 않은 경우 추가 컴파일 단계를 피하는 것이 좋습니다.
TarmoPikaro

114

개인적으로 C #을 스크립팅 언어로 사용합니다. .NET 프레임 워크 (및 Mono, Matthew Scharley 덕분에)는 실제로 프레임 워크 자체에 각 .NET 언어에 대한 컴파일러를 포함합니다.

기본적으로이 시스템의 구현에는 두 부분이 있습니다.

  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에서만 사용할 수 있는지 알고 있습니까?
Matthew Scharley

4
참고로, 다른 궁금한 사람에게는 예, 이것은 Mono에서 잘 컴파일되고 실행됩니다. 컴파일 부분에 대한 시스템 참조 만 필요합니다.
Matthew Scharley

3
이이 오염 AppDomain을 수행
다니엘 리틀

4
@Lavinski AppDomain을 오염시키지 않으려면 새 도메인을 만드십시오 (어쨌든 "스크립트"에 더 엄격한 보안을 적용 할 수있는 좋은 생각입니다)
Grant Peters

3
@Lander-이것은 매우 가볍습니다. 위의 코드는 "스크립팅"을 지원하는 전체 프로그램입니다. csscript.net이것에 대한 일종의 래퍼처럼 보입니다. 이것은 기본적으로 베어 본 구현입니다. 더 나은 질문은 "이것이 아닌 csscript.net이 나를 위해 무엇을 하는가"일 것입니다. 나는 csscript가 무엇을하는지 모르지만, 그들은 위의 코드가 무엇을하는지 확실히 알고 있습니다. 그들은 라이브러리에 그것을 가지고 있습니다.
Grant Peters


19

PowerShell 엔진은 스크립트가 가능하도록 응용 프로그램에 쉽게 포함되도록 설계되었습니다. 실제로 PowerShell CLI는 엔진에 대한 텍스트 기반 인터페이스입니다.

편집 : https://devblogs.microsoft.com/powershell/making-applications-scriptable-via-powershell/ 참조


AppDomain에 개체를 추가하지 않기 때문에 이것이 최상의 솔루션이라고 생각합니다. .Net에서는 어셈블리 나 클래스를 언로드 할 수 없습니다.
Daniel Little


8

제가 선택한 스크립팅 언어는 요즘 Lua 입니다. 작고 빠르며 깨끗하고 완벽하게 문서화되고 잘 지원되며 훌륭한 커뮤니티 가 있으며 업계의 많은 대기업에서 사용합니다. (Adobe, Blizzard, EA Games)에서 사용하고 있으며 시도해 볼 가치가 있습니다.

.NET 언어와 함께 사용하려면 LuaInterface 프로젝트가 필요한 모든 것을 제공합니다.


1
루아는 또한 훌륭한 게임입니다 :) 게리 모드에서 스크립트에 사용되는
익명의 겁쟁이



2

IronPython에 대한 또 다른 투표. 포함하는 것은 간단하고 .Net 클래스와의 상호 운용은 간단하며 Python입니다.


1

현재 유지하고있는 S # 을 제안 할 수 있습니다 . C #으로 작성되고 .NET 애플리케이션 용으로 설계된 오픈 소스 프로젝트입니다.

처음에는 (2007-2009) http://www.codeplex.com/scriptdotnet 에서 호스팅 되었지만 최근에는 github로 이동했습니다.


답변을 게시 해 주셔서 감사합니다! Self-Promotion에 대한 FAQ를 주의 깊게 읽어 보시기 바랍니다 . 또한 자신의 사이트 / 제품에 연결할 때마다 면책 조항을 게시 해야 합니다.
Andrew Barber

Andrew에게 조언을 해주셔서 감사합니다. 이전 답변 중 하나에이 스크립팅 언어에 대한 오래된 링크가 있습니다. 어떤 이유로 원래 답변에 댓글을 추가 할 수 없으므로 올바른 링크를 제공하기 위해 새 답변을 게시했습니다.
Peter



0

방금 클라이언트 용 플러그인을 만들어 VBA가 Office에서하는 것처럼 작동하는 모듈에 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.