Ngôn ngữ kịch bản tốt nhất để nhúng vào ứng dụng máy tính để bàn C # là gì? [đóng cửa]


98

Chúng tôi đang viết một ứng dụng phức tạp dành cho máy tính để bàn và cần phải cung cấp tính linh hoạt trong các định dạng báo cáo, vì vậy chúng tôi nghĩ rằng chúng tôi sẽ chỉ đưa mô hình đối tượng của mình vào một ngôn ngữ kịch bản. Thời gian là khi điều đó có nghĩa là VBA (vẫn là một tùy chọn), nhưng VSTA dẫn xuất mã được quản lý (tôi nghĩ) dường như đã khô héo trên cây nho.

Sự lựa chọn tốt nhất hiện nay cho một ngôn ngữ kịch bản nhúng trên Windows .NET là gì?


FWIW, tôi bắt đầu với cách tiếp cận trong câu trả lời của @ GrantPeter, đã sử dụng AppDomain để cho phép dỡ tải, xử lý việc gia hạn hợp đồng thuê đối tượng trên nhiều miền và tìm hiểu các biện pháp bảo mật hộp cát. Tập lệnh đã biên dịch có thể gọi các phương thức trong chương trình chính, ngược lại qua ranh giới AppDomain. Thí nghiệm có thể được tìm thấy ở đây: github.com/fadden/DynamicScriptSandbox
Fadden

Câu trả lời:


24

Tôi đã sử dụng CSScript với kết quả đáng kinh ngạc. Nó thực sự cắt giảm việc phải thực hiện các ràng buộc và những thứ cấp thấp khác trong các ứng dụng có thể tập lệnh của tôi.


1
Tôi đã sử dụng CS-Script trong sản xuất hơn một năm và nó hoạt động rất tốt.
David Robbins

Btw - để kích hoạt hỗ trợ tập lệnh C #, bạn có thể tích hợp thư viện tập lệnh C # vào bên trong hoặc tự biên dịch tập lệnh C #. Tôi đã thực hiện trình biên dịch tập lệnh C # nhẹ tương tự vào dự án của riêng mình tại đây: sourceforge.net/p/syncproj/code/HEAD/tree/CsScript.cs Bản thân việc biên dịch tập lệnh C # hơi chậm (ví dụ như so với .Lua), khiến để tránh bước biên dịch bổ sung nếu không cần thiết.
TarmoPikaro

114

Cá nhân tôi sử dụng C # làm ngôn ngữ kịch bản. Khuôn khổ .NET (và Mono, cảm ơn Matthew Scharley) thực sự bao gồm các trình biên dịch cho từng ngôn ngữ .NET trong chính khuôn khổ.

Về cơ bản, có 2 phần để thực hiện hệ thống này.

  1. Cho phép người dùng biên dịch mã Điều này tương đối dễ dàng và có thể được thực hiện chỉ trong một vài dòng mã (mặc dù bạn có thể muốn thêm hộp thoại lỗi, có thể sẽ là vài chục dòng mã nữa, tùy thuộc vào cách sử dụng bạn muốn nó được).

  2. Tạo và sử dụng các lớp có trong hợp ngữ đã biên dịch Việc này khó hơn một chút so với bước trước (yêu cầu một chút phản xạ). Về cơ bản, bạn chỉ nên coi hợp ngữ đã biên dịch như một "trình cắm thêm" cho chương trình. Có khá nhiều hướng dẫn về các cách khác nhau để bạn có thể tạo một hệ thống plug-in trong C # (Google là bạn của bạn).

Tôi đã triển khai một ứng dụng "nhanh" để chứng minh cách bạn có thể triển khai hệ thống này (bao gồm 2 tập lệnh làm việc!). Đây là mã hoàn chỉnh cho ứng dụng, chỉ cần tạo một mã mới và dán mã vào tệp "program.cs". Tại thời điểm này, tôi phải xin lỗi vì đoạn mã lớn mà tôi sắp dán (tôi không có ý định cho nó lớn như vậy, nhưng tôi đã nhận xét được một chút)


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
Bạn có biết nếu điều này cũng sẽ hoạt động trong Mono hay nó chỉ khả dụng trên .NET?
Matthew Scharley

4
FYI, và đối với bất kỳ ai khác tò mò, vâng, điều này thực sự biên dịch và chạy trên Mono tốt. Chỉ cần tham chiếu Hệ thống cho các phần biên dịch.
Matthew Scharley

3
Làm ô nhiễm này AppDomain
Daniel Ít

4
@Lavinski Nếu bạn không muốn nó làm ô nhiễm AppDomain của bạn, sau đó chỉ cần thực hiện một cái mới (mà có lẽ là một ý tưởng tốt anyway vì vậy bạn có thể đặt an ninh nghiêm ngặt hơn về "kịch bản")
Grant Peters

3
@Lander - Cái này cực kỳ nhẹ. Đoạn mã trên là toàn bộ chương trình hỗ trợ "script". csscript.netcó vẻ như đó là một loại trình bao bọc nào đó đối với điều này. Về cơ bản, đây là một cách triển khai cơ bản. Tôi nghĩ câu hỏi hay hơn sẽ là "csscript.net làm được gì cho tôi mà điều này thì không". Tôi không biết csscript đang làm gì, nhưng họ chắc chắn biết đoạn mã trên ở đây làm gì, họ có nó (hoặc một cái gì đó cực kỳ tương tự) trong thư viện của họ.
Grant Peters


19

Công cụ PowerShell được thiết kế để dễ dàng nhúng vào một ứng dụng để làm cho nó có thể viết được. Trên thực tế, PowerShell CLI chỉ là một giao diện dựa trên văn bản cho công cụ.

Chỉnh sửa: Xem https://devblogs.microsoft.com/powershell/making-application-scriptable-via-powershell/


Tôi nghĩ đây là giải pháp tốt nhất vì nó không thêm các đối tượng vào AppDomain. Trong .Net, bạn không bao giờ có thể dỡ bỏ các tập hợp hoặc lớp.
Daniel Little


8

Ngày nay, ngôn ngữ viết kịch bản của tôi sẽ là Lua . Nó nhỏ, nhanh, sạch, được ghi chép đầy đủ, được hỗ trợ tốt, có một cộng đồng lớn , được nhiều công ty lớn trong ngành sử dụng (Adobe, Blizzard, EA Games) sử dụng, chắc chắn đáng để thử.

Để sử dụng nó với các ngôn ngữ .NET, dự án LuaInterface sẽ cung cấp tất cả những gì bạn cần.


1
Lua cũng được sử dụng cho các kịch bản trong Mod Garry, mà là một trò chơi tuyệt vời :)
kẻ hèn nhát vô danh



2

Một phiếu bầu khác cho IronPython. Nhúng nó rất đơn giản, tương tác với các lớp .Net rất đơn giản và tốt, đó là Python.


1

Tôi có thể đề xuất S # mà tôi hiện đang duy trì. Nó là một dự án mã nguồn mở, được viết bằng C # và được thiết kế cho các ứng dụng .NET.

Ban đầu (2007-2009) nó được lưu trữ tại http://www.codeplex.com/scriptdotnet , nhưng gần đây nó đã được chuyển sang github.


Cảm ơn đã đăng câu trả lời của bạn! Hãy đảm bảo đọc kỹ Câu hỏi thường gặp về Tự quảng cáo . Cũng lưu ý rằng bạn bắt buộc phải đăng tuyên bố từ chối trách nhiệm mỗi khi bạn liên kết đến trang web / sản phẩm của chính mình.
Andrew Barber

Cảm ơn vì lời khuyên Andrew. Một trong những câu trả lời trước chứa liên kết lỗi thời tới ngôn ngữ kịch bản này. Vì một số lý do, tôi không thể thêm nhận xét vào câu trả lời ban đầu, vì vậy tôi đã đăng một câu mới để cung cấp liên kết chính xác.
Peter

1

Hãy thử Ela . Đây là một ngôn ngữ chức năng tương tự như Haskell và có thể được nhúng vào bất kỳ ứng dụng .Net nào. Thậm chí nó có IDE đơn giản nhưng có thể sử dụng được.



0

Tôi vừa tạo một plugin cho một máy khách, cho phép họ viết mã C # trong các mô-đun hoạt động giống như VBA cho Office.



0

Tôi thích viết kịch bản với chính C # . Bây giờ, vào năm 2013, có sự hỗ trợ khá tốt cho tập lệnh C #, ngày càng có nhiều thư viện cho nó.

Mono hỗ trợ tuyệt vời để viết mã C # và bạn có thể sử dụng nó với .NET chỉ bằng cách đưa Mono.CSharp.dllvào ứng dụng của mình. Đối với ứng dụng tập lệnh C # mà tôi đã thực hiện, hãy xem CShell

Ngoài ra, hãy kiểm tra ScriptEngine trong Roslyn của Microsoft, nhưng đây chỉ là CTP.

Như một số người đã đề cập, CS-Script cũng đã xuất hiện được một thời gian.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.