2008-09-26 63 views
93

Chúng tôi đang viết một ứng dụng máy tính để bàn phức tạp và cần phải cung cấp sự 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ỉ hiển thị mô hình đối tượng của mình cho một ngôn ngữ kịch bản. Thời gian là khi đó có nghĩa là VBA (mà vẫn còn là một lựa chọn), nhưng mã được quản lý phái sinh VSTA (tôi nghĩ) dường như đã héo trên cây nho.Ngôn ngữ kịch bản tốt nhất để nhúng vào ứng dụng C# trên máy tính để bàn là gì?

Lựa chọn nào tốt nhất cho ngôn ngữ kịch bản được nhúng trên Windows .NET?

+0

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 một AppDomain để cho phép dỡ hàng, xử lý việc gia hạn hợp đồng thuê miền chéo, và fiddled với các biện pháp an ninh sandbox. Kịch bản được biên dịch có thể gọi các phương thức trong chương trình chính, quay lại ranh giới AppDomain. Các thử nghiệm có thể được tìm thấy ở đây: https://github.com/fadden/DynamicScriptSandbox – fadden

Trả lời

21

Tôi đã sử dụng CSScript với kết quả tuyệt vời. Nó thực sự cắt giảm việc phải làm các ràng buộc và các công cụ cấp thấp khác trong các ứng dụng có thể chạy được của tôi.

+1

Tôi đã sử dụng CS-Script trong sản xuất trong hơn một năm và nó đã thực hiện rất tốt. –

1

JScript.NET là một tài khoản tốt. Fiddler sử dụng nó.

18

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

Chỉnh sửa: Xem http://blogs.msdn.com/powershell/archive/2007/08/29/making-applications-scriptable-via-powershell.aspx

+0

Tôi nghĩ rằng đây là giải pháp tốt nhất bởi 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 hội đồng hoặc các lớp học. –

2

IronRuby như đã đề cập ở trên. Một dự án thú vị đối với tôi với tư cách lập trình viên C# là C# Eval support in Mono. Nhưng nó chưa có sẵn (sẽ là một phần của Mono 2.2).

13

Boo ngôn ngữ.

+1

Có vẻ như đã chết nếu đó là dự án tại https://github.com/boo-lang/boo – kristianp

+0

@kristianp hiện tại, có một vài cam kết mỗi tháng trong dự án (cho đến gần đây như một tháng trước). Vì vậy, có lẽ nó đã mất một chút lực kéo, nhưng nó vẫn có vẻ còn sống. –

0

Tôi vừa tạo một plugin cho một khách hàng, cho phép họ viết mã # C trong module mà hành động như VBA không cho Office .

8

Ngôn ngữ kịch bản lệnh lựa chọn của tôi sẽ là Lua những ngày này. Nó nhỏ gọn, nhanh chóng, sạch sẽ, đầy đủ tài liệu, được hỗ trợ tốt, có số lượng lớn community, được sử dụng bởi nhiều công ty lớn trong số industry (Adobe, Blizzard, EA Games), đáng để thử.

Để sử dụng với 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 kịch bản trong Garry's Mod, đó là một trò chơi tuyệt vời :) –

2

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

105

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

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

  1. Cho phép người sử dụng để biên dịch mã Đây là 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 một hộp thoại báo lỗi, mà có lẽ sẽ là một vài chục hơn dòng mã, tùy thuộc vào cách bạn có thể sử dụng được).

  2. Tạo và sử dụng các lớp chứa trong assembly được biên dịch Điều 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ỉ cần xử lý assembly được biên dịch như là một "plug-in" cho chương trình. Có khá nhiều hướng dẫn về nhiều cách khác nhau để bạn có thể tạo một hệ thống trình cắm thêm trong C# (Google là bạn của bạn).

Tôi đã triển khai ứng dụng "nhanh" để minh họa cách bạn có thể triển khai hệ thống này (bao gồm 2 tập lệnh hoạt động!). Đây là mã hoàn chỉnh cho ứng dụng, chỉ cần tạo 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ì sự phần lớn mã Tôi về để dán (Tôi không có ý định cho nó là quá lớn, nhưng có một chút mang đi với bình luận của tôi)

 

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 điều này cũng có hiệu quả trong Mono hay chỉ có trên .NET? –

+0

tôi không biết, không bao giờ sử dụng Mono –

+4

FYI, và cho bất kỳ ai khác mà tò mò, có, điều này không 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. –

0

tôi đã từng sử dụng Lua trước đó; trong một ứng dụng Delphi nhưng nó có thể được nhúng vào rất nhiều thứ. Nó được sử dụng trong Adobe's Photoshop Lightroom.

1

Tôi có thể đề xuất S# mà tôi hiện đang duy trì. Nó là một dự án 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 đến github.

+0

Cảm ơn bạn đã đăng câu trả lời! Vui lòng đảm bảo đọc kỹ [FAQ on Self-Promotion] (http://stackoverflow.com/faq#promotion). Cũng lưu ý rằng nó là * bắt buộc * mà bạn đăng tuyên bố từ chối trách nhiệm mỗi lần bạn liên kết đến trang web/sản phẩm của riêng bạn. –

+0

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

0

Tôi thích tập lệnh với chính C#. Bây giờ, trong năm 2013, có hỗ trợ khá tốt cho C# scripting, ngày càng nhiều thư viện cho nó đang trở nên có sẵn.

Mono có hỗ trợ tuyệt vời cho script C# code và bạn có thể sử dụng nó bằng .NET bằng cách chỉ bao gồm Mono.CSharp.dll trong đơn đăng ký của mình. Đối với ứng dụng C# scripting mà tôi đã thực hiện, hãy kiểm tra CShell

Ngoài ra, hãy kiểm tra `ScriptEngine 'trong Roslyn từ Microsoft, nhưng đây chỉ là CTP.

Như một số người đã đề cập, CS-Script đã được sử dụng trong một thời gian ngắn.

1

Hãy thử Ela. Đây là một ngôn ngữ chức năng tương tự như Haskell và có thể là embedded 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.

Các vấn đề liên quan