2008-09-10 86 views
43

Tôi muốn làm tương đương với:Làm cách nào để đánh giá biểu thức C#?

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

Sau Biri s link, tôi đã đoạn này (sửa đổi để loại bỏ phương pháp lỗi thời ICodeCompiler.CreateCompiler():

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

Tại sao điều này lại cần thiết? Tôi rất nghi ngờ rằng đây là thiết kế tốt nhất cho bất kỳ mục đích nào bạn có ý định. Nhiều khả năng có các cơ chế khác để tạo ra các kết quả mà bạn mong muốn mà không cần mở một lượng lớn các sâu (để bảo mật và bảo trì) đang đánh giá các đoạn mã trong thời gian chạy. – Wedge

+0

Tôi muốn một cách nhanh chóng và bẩn để thêm xác nhận biểu thức vào một DSL tôi đã viết. Tôi kiểm soát các tập tin được cho ăn để đánh giá, do đó, các worms không bao giờ được mở;) Ngoài ra, tôi chỉ cho phép một biểu thức, không thêm bất kỳ Không gian tên/tham chiếu bất kỳ hội đồng. Điều này sẽ ngăn bản thân mình khỏi làm hại! –

+1

Tôi thực hiện việc này trong các tình huống thử nghiệm. Tôi có một hội đồng thay đổi số phiên bản khi nó được cập nhật. Tôi muốn mã thử nghiệm của tôi bị "ràng buộc trễ" với hội đồng - để có thể nạp lắp ráp và gọi nó vào động. đây là một vấn đề phản chiếu đơn giản. Nhưng khi tôi muốn thực hiện một giao diện được chỉ định trong hội đồng, nó đòi hỏi biên dịch mã động, bởi vì giao diện chính nó si mạnh mẽ được đặt tên (với một số phiên bản). Tôi không thể có mã thực hiện IFoo v1.2 khi tôi muốn gọi v1.3. Biên dịch động sẽ giải quyết vấn đề này. – Cheeso

Trả lời

32

Bằng việc sử dụng biên dịch một cách nhanh chóng, giống như this example hiển thị

Hoặc bằng cách sử dụng Flee, lý do chính xác cho cùng một lý do.

1

Ý nghĩa hiệu suất của việc này là gì?

Chúng tôi sử dụng hệ thống dựa trên nội dung như đã đề cập ở trên, mỗi tập lệnh C# được biên dịch vào một bộ nhớ trong và được thực hiện trong một AppDomain riêng biệt. Không có hệ thống bộ nhớ đệm nào được nêu ra, vì vậy các tập lệnh được biên dịch lại mỗi khi chúng chạy. Tôi đã thực hiện một số thử nghiệm đơn giản và kịch bản "Hello World" rất đơn giản biên dịch trong khoảng 0,7 giây trên máy tính của tôi, bao gồm tải tập lệnh từ đĩa. 0,7 giây là tốt cho một hệ thống kịch bản, nhưng có thể là quá chậm để đáp ứng đầu vào của người dùng, trong trường hợp đó một trình phân tích/trình biên dịch chuyên dụng như Flee có thể tốt hơn.

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

Có vẻ như cũng có cách làm việc đó bằng cách sử dụng RegEx và XPathNavigator để đánh giá biểu thức. Tôi đã không có cơ hội để kiểm tra nó được nêu ra nhưng tôi thích nó vì nó không yêu cầu biên dịch mã tại thời gian chạy hoặc sử dụng các thư viện mà không thể có sẵn.

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

Tôi sẽ dùng thử và cho biết sau nếu nó hoạt động. Tôi cũng có ý định thử nó trong Silverlight, nhưng đã quá trễ và tôi gần như ngủ để làm điều đó ngay bây giờ.

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

Có một triển khai JavaScript tốt hơn được gọi là Iron JS. Nó sử dụng DLR như Iron Python, vv [Iron Js trên NuGet] (http://nuget.org/List/Packages/IronJS). Khi tôi hiểu Vsa đã lỗi thời –

1

Mặc dù C# không có bất kỳ hỗ trợ nào cho phương pháp Eval, nhưng tôi có chương trình C# eval cho phép đánh giá mã C#. Nó cung cấp để đánh giá mã C# khi chạy và hỗ trợ nhiều câu lệnh C#. Trên thực tế, mã này có thể sử dụng được trong bất kỳ dự án .NET nào, tuy nhiên, nó được giới hạn sử dụng cú pháp C#. Hãy xem trang web của tôi, http://csharp-eval.com để biết thêm chi tiết.

20

Tôi đã viết một dự án mã nguồn mở, Dynamic Expresso, có thể chuyển đổi biểu thức văn bản được viết bằng cú pháp C# thành các đại biểu (hoặc cây biểu thức). Các biểu thức văn bản được phân tích cú pháp và chuyển đổi thành Expression Trees mà không cần sử dụng biên dịch hoặc phản chiếu.

Bạn có thể viết một cái gì đó như:

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

hoặc

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); 

Công việc của tôi được dựa trên Scott Gu bài viết http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx.

+0

+1 - Tôi đã thử dự án này ... tuyệt vời! – pilotcam

+0

+1 @Davide lcardi đó là thư viện rất tốt, nhưng có một số hạn chế: https://stackoverflow.com/questions/46581067/how-to-make-dynamicexpresso-recognizes-members-using-new-modifier – Dabbas

9

Chủ đề cũ, nhưng xem xét đây là một trong những chủ đề đầu tiên hiển thị khi googling, đây là một giải pháp được cập nhật.

Bạn có thể sử dụng Roslyn's new Scripting API to evaluate expressions.

Nếu bạn đang sử dụng NuGet, chỉ cần thêm phụ thuộc vào Microsoft.CodeAnalysis.CSharp.Scripting. Để đánh giá các ví dụ mà bạn cung cấp, nó cũng đơn giản như:

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

Điều này rõ ràng không tận dụng khả năng async các đoạn mã script của.

Bạn cũng có thể xác định loại kết quả đánh giá như bạn dự định:

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

Để đánh giá các đoạn mã tiên tiến hơn, vượt qua các thông số, cung cấp tài liệu tham khảo, không gian tên và không có điều gì, kiểm tra wiki liên kết ở trên.

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