Bir C # masaüstü uygulamasına gömmek için en iyi komut dosyası dili nedir? [kapalı]


98

Karmaşık, zengin bir masaüstü uygulaması yazıyoruz ve raporlama biçimlerinde esneklik sunmamız gerekiyor, bu nedenle nesne modelimizi bir komut dosyası diline maruz bırakacağımızı düşündük. Zaman, bunun VBA anlamına geldiği zamandı (ki bu hala bir seçenektir), ancak yönetilen kod türevi VSTA (sanırım) asma üzerinde solmuş gibi görünüyor.

Windows .NET üzerinde gömülü bir betik dili için şimdi en iyi seçenek nedir?


FWIW, @ GrantPeter'ın cevabındaki yaklaşımla başladım, boşaltmaya izin vermek için bir AppDomain kullandım, etki alanları arası nesne kiralama yenilemesini ele aldım ve sandbox güvenlik önlemleriyle uğraştım. Derlenen betik, ana programdaki yöntemleri AppDomain sınırının ötesine geri çağırabilir. Deney burada bulunabilir: github.com/fadden/DynamicScriptSandbox
fadden

Yanıtlar:


24

Harika sonuçlarla CSScript kullandım . Komut dosyası oluşturulabilir uygulamalarımda bağlama ve diğer düşük seviyeli şeyler yapma zorunluluğunu gerçekten azalttı.


1
CS-Script'i bir yılı aşkın süredir üretimde kullanıyorum ve gerçekten iyi performans gösterdi.
David Robbins

Btw - C # komut dosyası desteğini etkinleştirmek için C # komut dosyası kitaplığını içine entegre edebilir veya kendi başınıza C # komut dosyası derlemesi yapabilirsiniz. Buradaki kendi projeme benzer hafif C # komut dosyası derleyicisini yaptım: sourceforge.net/p/syncproj/code/HEAD/tree/CsScript.cs C # komut dosyası derlemesinin kendisi biraz yavaş (örneğin .Lua ile karşılaştırıldığında), yapar Gerekmiyorsa ekstra derleme adımından kaçınmak için mantıklı.
TarmoPikaro

114

Şahsen, betik dili olarak C # kullanırım. .NET çerçevesi (ve Mono, teşekkürler Matthew Scharley) aslında çerçevenin kendisinde .NET dillerinin her biri için derleyiciler içerir.

Temel olarak, bu sistemin uygulanmasının 2 bölümü var.

  1. Kullanıcının kodu derlemesine izin verin Bu nispeten kolaydır ve yalnızca birkaç satır kodla yapılabilir (ancak ne kadar kullanılabilir olduğuna bağlı olarak muhtemelen birkaç düzine daha fazla kod satırı olacak bir hata iletişim kutusu eklemek isteyebilirsiniz. olmasını istiyorsun).

  2. Derlenmiş derlemede bulunan sınıfları oluşturun ve kullanın Bu, önceki adımdan biraz daha zordur (küçük bir yansıma gerektirir). Temel olarak, derlenmiş derlemeyi program için bir "eklenti" olarak görmelisiniz. C #'da bir eklenti sistemi oluşturmanın çeşitli yollarıyla ilgili epeyce eğitim var (Google arkadaşınızdır).

Bu sistemi nasıl uygulayabileceğinizi göstermek için "hızlı" bir uygulama uyguladım (2 çalışan komut dosyası içerir!). Bu, uygulamanın tam kodudur, sadece yeni bir tane oluşturun ve kodu "program.cs" dosyasına yapıştırın. Bu noktada yapıştırmak üzere olduğum büyük kod parçası için özür dilemeliyim (bu kadar büyük olmasını istemedim, ancak yorumuma biraz kapıldım)


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
Bunun Mono'da da çalışıp çalışmayacağını biliyor musunuz, yoksa yalnızca .NET'te mi kullanılabilir?
Matthew Scharley

4
Bilginize ve meraklı olan herkes için, evet, bu Mono üzerinde derlenir ve çalışır. Derleme parçaları için yalnızca Sistem referansına ihtiyaç vardır.
Matthew Scharley

3
Bunu yapmak AppDomain'i kirletiyor
Daniel Little

4
@Lavinski AppDomain'inizi kirletmesini istemiyorsanız, yeni bir tane oluşturun (bu muhtemelen iyi bir fikirdir, böylece "komut dosyalarına" daha sıkı güvenlik koyabilirsiniz)
Grant Peters

3
@Lander - Bu son derece hafif. Yukarıdaki kod, "komut dosyası oluşturmayı" destekleyen bütün bir programdır. csscript.netGörünüşe göre bunun üzerinde bir çeşit paket var. Bu temelde basit bir uygulamadır. Bence daha iyi bir soru "csscript.net benim için ne yapar, bu yapmaz" olur. Csscript'in ne yaptığını bilmiyorum, ama buradaki kodun ne yaptığını kesinlikle biliyorlar, kütüphanelerinde (veya son derece benzer bir şey) var.
Grant Peters


19

PowerShell motoru, komut dosyası yazılabilir hale getirmek için bir uygulamaya kolayca yerleştirilecek şekilde tasarlanmıştır. Aslında, PowerShell CLI, motor için yalnızca metin tabanlı bir arabirimdir.

Düzenleme: Bkz. Https://devblogs.microsoft.com/powershell/making-applications-scriptable-via-powershell/


Bunun en iyi çözüm olduğunu düşünüyorum çünkü AppDomain'e nesne eklemiyor. .Net'te derlemeleri veya sınıfları asla kaldıramazsınız.
Daniel Little


8

Bu günlerde tercih ettiğim senaryo dili Lua olacak . Küçük, hızlı, temiz, tam olarak belgelenmiş, iyi desteklenmiş, harika bir topluluğa sahip , sektördeki birçok büyük şirket (Adobe, Blizzard, EA Games) tarafından kullanılıyor, kesinlikle denemeye değer.

Bunu .NET dilleriyle kullanmak için LuaInterface projesi ihtiyacınız olan her şeyi sağlayacaktır.


1
Lua ayrıca harika bir oyun olan Garry's Modunda komut dosyası yazmak için de kullanılıyor :)
anonim korkak



2

IronPython için bir oy daha. Bunu yerleştirmek basittir, .Net sınıflarıyla birlikte çalışmak basittir ve Python'dur.


1

S # önerebilirimŞu anda sürdürdüğüm . C # ile yazılmış ve .NET uygulamaları için tasarlanmış açık kaynak kodlu bir projedir.

Başlangıçta (2007-2009) http://www.codeplex.com/scriptdotnet adresinde barındırılıyordu , ancak yakın zamanda github'a taşındı.


Cevabınızı gönderdiğiniz için teşekkürler! Lütfen Kendini Tanıtma ile ilgili SSS'yi dikkatlice okuduğunuzdan emin olun . Ayrıca , kendi sitenize / ürününüze her bağlandığınızda bir sorumluluk reddi beyanı göndermeniz gerektiğini unutmayın .
Andrew Barber

Tavsiye için teşekkürler Andrew. Önceki cevaplardan biri, bu komut dosyası diline güncel olmayan bir bağlantı içeriyor. Bazı nedenlerden dolayı orijinal cevaba yorum ekleyemiyorum, bu yüzden doğru bağlantıyı sağlamak için yeni bir tane gönderdim.
Peter



0

Bir istemci için, VBA'nın Office için yaptığı gibi davranan modüllerde C # kodu yazmalarına izin veren bir eklenti oluşturdum.



0

C # ile komut dosyası yazmayı seviyorum . Şimdi, 2013'te, C # komut dosyası oluşturma için oldukça iyi bir destek var ve bunun için gittikçe daha fazla kitaplık kullanıma sunuluyor.

Mono, C # kodunun komut dosyası için harika bir desteğe sahiptir ve bunu yalnızca Mono.CSharp.dlluygulamanıza ekleyerek .NET ile kullanabilirsiniz . Kontrol ettiğim C # komut dosyası uygulaması için CShell'e atın

Ayrıca `ScriptEngine' check out Roslyn Microsoft'tan, ama bu sadece CTP olduğunu.

Bazı kişilerin daha önce de belirttiği gibi, CS-Script de bir süredir ortalıkta.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.