2008-09-10 21 views
43

Ben eşdeğer yapmak istiyorum: gibi, anında derleme kullanarakC# ifadesini dinamik olarak nasıl değerlendirebilirim?

private object Eval(string sExpression) 
{ 
    CSharpCodeProvider c = new CSharpCodeProvider(); 
    CompilerParameters cp = new CompilerParameters(); 

    cp.ReferencedAssemblies.Add("system.dll"); 

    cp.CompilerOptions = "/t:library"; 
    cp.GenerateInMemory = true; 

    StringBuilder sb = new StringBuilder(""); 
    sb.Append("using System;\n"); 

    sb.Append("namespace CSCodeEvaler{ \n"); 
    sb.Append("public class CSCodeEvaler{ \n"); 
    sb.Append("public object EvalCode(){\n"); 
    sb.Append("return " + sExpression + "; \n"); 
    sb.Append("} \n"); 
    sb.Append("} \n"); 
    sb.Append("}\n"); 

    CompilerResults cr = c.CompileAssemblyFromSource(cp, sb.ToString()); 
    if (cr.Errors.Count > 0) 
    { 
     throw new InvalidExpressionException(
      string.Format("Error ({0}) evaluating: {1}", 
      cr.Errors[0].ErrorText, sExpression)); 
    } 

    System.Reflection.Assembly a = cr.CompiledAssembly; 
    object o = a.CreateInstance("CSCodeEvaler.CSCodeEvaler"); 

    Type t = o.GetType(); 
    MethodInfo mi = t.GetMethod("EvalCode"); 

    object s = mi.Invoke(o, null); 
    return s; 

} 
+0

Bu neden gereklidir? Bu, niyetiniz ne olursa olsun, en iyi tasarımın olduğundan şüphe duyuyorum. Büyük olasılıkla, kod parçacıklarını çalışma zamanında değerlendiren büyük miktarda solucan (güvenlik ve bakım için) açmadan istediğiniz sonuçları üretmek için başka mekanizmalar da vardır. – Wedge

+0

Yazdığım bir DSL'ye ifade doğrulaması eklemenin hızlı ve kirli bir yolunu istedim. Değerlendiriciye beslenen dosyaları kontrol ediyorum, böylece solucanlar kutusu hiçbir zaman açılmıyor;) Ayrıca, sadece bir ifadeye izin veriyorum, herhangi bir İsim ekleyemem/herhangi bir derleme göndermem. Bu kendimi de zarar vermekten alıkoymalıdır! –

+1

Bunu test senaryolarında yapıyorum. Güncellenen sürüm numaralarını değiştiren bir derlemem var. Montaj kodumun montajı yapabilmesi ve dinamik olarak çağırabilmesi için test kodumun meclise "geç bağlı" olmasını isterim. Bu basit bir yansıma meselesidir. Ancak, derlemede belirtilen bir arabirimi uygulamak istediğimde, arabirimin kendisi güçlü bir şekilde (sürüm numarasıyla) adlandırıldığı için, kodun dinamik olarak derlenmesi gerekir. V1.3'ü çağırmak istediğimde IFoo v1.2'yi uygulayan bir kodum olamaz. Dinamik derleme bunu ele alır. – Cheeso

cevap

32

: Biri s link ardından

object result = Eval("1 + 3"); 
string now = Eval("System.DateTime.Now().ToString()") as string 

, ben eskimiş yöntem ICodeCompiler.CreateCompiler() kaldırmak için modifiye bu pasajı (var this example gösterir.

Ya tam olarak aynı nedenden dolayı olan Flee kullanarak.

1

Bunu yapmanın performans sonuçları nelerdir?

Her C# komut bir bellek içi montaja derlenmiş ve ayrı bir AppDomain içinde yürütülür yukarıda belirtilen gibi bir şey dayanan bir sistem kullanırlar. Henüz önbellekleme sistemi yok, bu yüzden scriptler her çalıştığında yeniden derleniyor. Bazı basit testler yaptım ve çok basit bir "Merhaba Dünya" betiği, komut dosyasını diskten yüklemek de dahil olmak üzere makinemde yaklaşık 0.7 saniyede derleniyor. Bir betik sistemi için 0.7 saniye iyidir, ancak kullanıcı girdisine yanıt vermek için çok yavaş olabilir, bu durumda Flee gibi özel bir ayrıştırıcı/derleyici daha iyi olabilir.

using System; 
public class Test 
{ 
    static public void DoStuff(Scripting.IJob Job) 
    { 
     Console.WriteLine("Heps"); 
    } 
} 
0

Ayrıca ifadeyi değerlendirmek için RegEx ve XPathNavigator kullanarak bunu yapmanın bir yolu var gibi görünüyor. Bunu henüz test etme şansım olmadı ama ben bunu sevdim çünkü çalışma zamanında kod derlemem ya da mevcut olmayan kütüphaneleri kullanmam gerekiyordu.

http://www.webtips.co.in/c/evaluate-function-in-c-net-as-eval-function-in-javascript.aspx

ben denemek ve işe yaradı eğer sonradan anlatacağım. Ayrıca Silverlight'ta denemek niyetindeyim, ama çok geç ve neredeyse bunu yapmak için neredeyse uyuyorum.

2
using System; 
using Microsoft.JScript; 
using Microsoft.JScript.Vsa; 
using Convert = Microsoft.JScript.Convert; 

namespace System 
{ 
    public class MathEvaluator : INeedEngine 
    { 
     private VsaEngine vsaEngine; 

     public virtual String Evaluate(string expr) 
     { 
      var engine = (INeedEngine)this; 
      var result = Eval.JScriptEvaluate(expr, engine.GetEngine()); 

      return Convert.ToString(result, true); 
     } 

     VsaEngine INeedEngine.GetEngine() 
     { 
      vsaEngine = vsaEngine ?? VsaEngine.CreateEngineWithType(this.GetType().TypeHandle); 
      return vsaEngine; 
     } 

     void INeedEngine.SetEngine(VsaEngine engine) 
     { 
      vsaEngine = engine; 
     } 
    } 
} 
+0

Demir JS denilen daha iyi bir JavaScript uygulaması var. DLR gibi Demir Python, vb. [NuGet üzerinde Iron Js] (http://nuget.org/List/Packages/IronJS) kullanılır. Anladığım kadarıyla Vsa eski –

1

C#, bir Eval yöntemi için yerel olarak herhangi bir destek almazken, C# kodunun değerlendirilmesine izin veren bir C# eval programım var. C# kodunu çalışma zamanında değerlendirir ve birçok C# ifadesini destekler. Aslında, bu kod herhangi bir .NET projesinde kullanılabilir, ancak C# sözdizimini kullanmakla sınırlıdır. Ek ayrıntılar için web siteme http://csharp-eval.com bir göz atın.

20

Açık bir kaynak proje, Dynamic Expresso yazdım, bu C# sözdizimi kullanılarak yazılmış metin ifadesini delegelere (veya ifade ağacına) dönüştürebilir. Metin ifadeleri, derleme ve yansıma kullanmadan Expression Trees'a dönüştürülür ve dönüştürülür.

var interpreter = new Interpreter(); 
var result = interpreter.Eval("8/2 + 2"); 

veya

var interpreter = new Interpreter() 
       .SetVariable("service", new ServiceExample()); 

string expression = "x > 4 ? service.aMethod() : service.AnotherMethod()"; 

Lambda parsedExpression = interpreter.Parse(expression, 
         new Parameter("x", typeof(int))); 

parsedExpression.Invoke(5); 

İşim Scott Gu maddeye http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx dayanmaktadır:

Sen gibi bir şey yazabilirsiniz.

+0

+1 - Bu projeyi denedim ... fantastik! – pilotcam

+0

+1 @Davide lcardi çok iyi bir kütüphanedir, ancak bazı sınırlamaları vardır: https://stackoverflow.com/questions/46581067/how-to-make-dynamicexpresso-recognizes-members-using-new-modifier – Dabbas

9

Eski konu, ancak googling yaparken ortaya çıkan ilk konulardan biri göz önüne alındığında, işte güncelleştirilmiş bir çözüm.

Roslyn's new Scripting API to evaluate expressions'u kullanabilirsiniz.

NuGet'i kullanıyorsanız, yalnızca Microsoft.CodeAnalysis.CSharp.Scripting'a bir bağımlılık ekleyin. Bu tabii ki betik motorun zaman uyumsuz yetenekleri kullanımı yapmaz

var result = CSharpScript.EvaluateAsync("1 + 3").Result; 

: o kadar basittir, sağlanan örnekler değerlendirmek. ,

var now = CSharpScript.EvaluateAsync<string>("System.DateTime.Now.ToString()").Result; 

daha gelişmiş kod parçacıkları değerlendirmek parametrelerini geçirmek, referanslar, ad alanları ve etajer sağlamak, yukarıda bağlantılı wiki kontrol edin:

Ayrıca amaçlandığı gibi değerlendirilen sonuç türünü belirtebilirsiniz.

İlgili konular