ภาษาสคริปต์ที่ดีที่สุดในการฝังในแอปพลิเคชัน C # บนเดสก์ท็อปคืออะไร [ปิด]


98

เรากำลังเขียนแอปพลิเคชันเดสก์ท็อปที่มีความซับซ้อนและจำเป็นต้องให้ความยืดหยุ่นในรูปแบบการรายงานดังนั้นเราจึงคิดว่าเราจะเปิดเผยโมเดลอ็อบเจ็กต์ของเรากับภาษาสคริปต์ เวลานั้นหมายถึง VBA (ซึ่งยังคงเป็นตัวเลือก) แต่ VSTA อนุพันธ์ของรหัสที่มีการจัดการ (ฉันคิดว่า) ดูเหมือนจะเหี่ยวแห้งไปแล้ว

ตอนนี้ตัวเลือกที่ดีที่สุดสำหรับภาษาสคริปต์แบบฝังใน Windows .NET คืออะไร


FWIW ฉันเริ่มต้นด้วยแนวทางในคำตอบของ @ GrantPeter ใช้ AppDomain เพื่ออนุญาตการขนถ่ายจัดการการต่ออายุการเช่าวัตถุข้ามโดเมนและดำเนินการตามมาตรการรักษาความปลอดภัยของแซนด์บ็อกซ์ สคริปต์ที่คอมไพล์แล้วสามารถเรียกใช้เมธอดในโปรแกรมหลักกลับข้ามขอบเขต AppDomain สามารถดูการทดลองได้ที่นี่: github.com/fadden/DynamicScriptSandbox
fadden

คำตอบ:


24

ฉันใช้CSScriptกับผลลัพธ์ที่น่าทึ่ง มันช่วยลดการต้องทำการผูกและสิ่งอื่น ๆ ระดับต่ำในแอพที่สามารถเขียนสคริปต์ของฉันได้


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 framework (และ 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
Matthew Scharley

4
FYI และสำหรับใครก็ตามที่อยากรู้อยากเห็นใช่สิ่งนี้จะรวบรวมและรันบน Mono ได้ดี ต้องการการอ้างอิงระบบสำหรับส่วนการคอมไพล์เท่านั้น
Matthew Scharley

3
การทำเช่นนี้ก่อให้เกิดมลพิษต่อ AppDomain
Daniel Little

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

12

ภาษาBoo .


1
ดูเหมือนจะตายถ้าเป็นโครงการที่github.com/boo-lang/boo
kristianp

@kristianp ณ ตอนนี้มีการคอมมิตทุกเดือนในโครงการ (จนกระทั่งเร็ว ๆ นี้เมื่อ 1 เดือนที่แล้ว) ดังนั้นบางทีมันอาจจะสูญเสียแรงฉุดไปบ้าง แต่มันก็ยังมีชีวิตอยู่
Tamás Szelei

8

ภาษาสคริปต์ของฉันที่ฉันเลือกคือLua ในทุกวันนี้ มีขนาดเล็กรวดเร็วสะอาดมีเอกสารรองรับอย่างดีมีชุมชนที่ยอดเยี่ยมบริษัท ใหญ่ ๆ หลายแห่งในอุตสาหกรรมใช้งาน (Adobe, Blizzard, EA Games) คุ้มค่าที่จะลอง

หากต้องการใช้กับภาษา. NET โครงการLuaInterfaceจะมอบทุกสิ่งที่คุณต้องการ


1
Lua ยังใช้สำหรับการเขียนสคริปต์ใน Garry's Mod ซึ่งเป็นเกมที่ยอดเยี่ยม :)
คนขี้ขลาดที่ไม่เปิดเผยตัว


2

IronRuby ดังกล่าวข้างต้น. โครงการที่น่าสนใจให้ฉันเป็นโปรแกรมเมอร์ C # สนับสนุน C # Eval ในโมโน แต่ยังไม่พร้อมใช้งาน (จะเป็นส่วนหนึ่งของ Mono 2.2)



1

ฉันอาจแนะนำS #ที่ฉันดูแลอยู่ เป็นโครงการโอเพ่นซอร์สเขียนด้วยภาษา C # และออกแบบมาสำหรับแอปพลิเคชัน. NET

เริ่มแรก (2550-2552) โฮสต์ที่http://www.codeplex.com/scriptdotnetแต่เมื่อไม่นานมานี้ได้ย้ายไปที่ github


ขอบคุณสำหรับการโพสต์คำตอบของคุณ! โปรดอ่านคำถามที่พบบ่อยเกี่ยวกับการส่งเสริมตนเองอย่างละเอียด โปรดทราบว่าคุณจำเป็นต้องโพสต์ข้อจำกัดความรับผิดชอบทุกครั้งที่คุณเชื่อมโยงไปยังไซต์ / ผลิตภัณฑ์ของคุณเอง
Andrew Barber

ขอบคุณสำหรับคำแนะนำแอนดรู หนึ่งในคำตอบก่อนหน้านี้มีลิงก์ที่ล้าสมัยไปยังภาษาสคริปต์นี้ ด้วยเหตุผลบางประการฉันไม่สามารถเพิ่มความคิดเห็นในคำตอบเดิมได้ฉันจึงโพสต์ใหม่เพื่อให้ลิงก์ที่ถูกต้อง
ปีเตอร์

1

ลองEla นี่เป็นภาษาที่ใช้งานได้คล้ายกับ Haskell และสามารถฝังลงในแอปพลิเคชัน. Net ใดก็ได้ แม้จะมี IDE ที่เรียบง่าย แต่ใช้งานได้



0

ฉันเพิ่งสร้างปลั๊กอินสำหรับไคลเอนต์เพื่อให้พวกเขาสามารถเขียนโค้ด C # ในโมดูลที่ทำหน้าที่เหมือนกับ VBA สำหรับ Office



0

ฉันชอบการเขียนสคริปต์ด้วย C # ตัวเอง ตอนนี้ในปี 2013 มีการรองรับการเขียนสคริปต์ C # เป็นอย่างดีและมีไลบรารีมากขึ้นเรื่อย ๆ

Mono มีการสนับสนุนที่ดีเยี่ยมสำหรับสคริปต์รหัส C #และคุณสามารถใช้กับ. NET ได้เพียงแค่ใส่Mono.CSharp.dllในแอปพลิเคชันของคุณ สำหรับแอปพลิเคชันสคริปต์ C # ที่ฉันได้ตรวจสอบCShell

ตรวจสอบ `` ScriptEngine 'ในRoslynซึ่งมาจาก Microsoft แต่นี่เป็นเพียง CTP เท่านั้น

ดังที่บางคนได้กล่าวไปแล้วCS-Scriptก็มีมาระยะหนึ่งแล้วเช่นกัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.