2008-12-06 29 views
18

Tôi đang sử dụng C# với .NET 3.5. Có thể serialize một khối mã, truyền nó ở đâu đó, deserialize nó, và sau đó thực hiện nó?Có thể tuần tự hóa khối mã C# không?

Một cách sử dụng ví dụ về này sẽ là:

Action<object> pauxPublish = delegate(object o) 
{ 
    if (!(o is string)) 
    { 
     return; 
    } 
    Console.WriteLine(o.ToString()); 
}; 
Transmitter.Send(pauxPublish); 

Với một số chương trình từ xa thực hiện:

var action = Transmitter.Recieve(); 
action("hello world"); 

mục tiêu cuối cùng của tôi là để có thể thực thi mã tùy ý trong một quá trình khác nhau (trong đó có không có kiến ​​thức trước về mã).

+0

Khi làm việc cho khách hàng phải xử lý hàng nghìn tệp nhập mỗi ngày từ một vài trăm nguồn, tôi đã tạo công cụ nhập chung nơi người dùng nâng cao được phép xác định cột tệp và nhập dòng C# để chuyển đổi đầu vào giá trị cho loại/định dạng thích hợp. Khi định nghĩa mới được lưu, chúng tôi sẽ tự động biên dịch lớp nhập cho nguồn này, sau đó thực hiện nó khi các tệp mới đến. Với 50 trường hợp phổ biến tự động hoàn thành, nó hoạt động khá tốt và lưu rất nhiều yêu cầu thay đổi, cũng như cải thiện tốc độ nhập theo thứ tự độ lớn. – Basic

Trả lời

15

CÓ !!!

Chúng tôi đã thực hiện việc này cho một trường hợp rất thực tế về hiệu suất. Làm điều này trong thời gian chạy hoặc sử dụng DSL không phải là một tùy chọn do hiệu suất.

Chúng tôi biên dịch mã thành một assembly và tách IL ra khỏi phương thức.Sau đó chúng tôi nhận được tất cả các siêu dữ liệu liên kết với phương pháp này và serialize toàn bộ mess thông qua XML, nén nó, và đặt nó trong cơ sở dữ liệu của chúng tôi.

Khi thời gian tái hydrat hóa, chúng tôi sẽ tạo thành IL bằng siêu dữ liệu bằng cách sử dụng lớp DynamicMethod và thực thi nó.

Chúng tôi làm điều này vì tốc độ. Chúng tôi có hàng ngàn khối mã nhỏ. Thật không may, để biên dịch một khối mã và chạy nó trên bay mất ít nhất 250 ms, đó là cách quá chậm đối với chúng tôi. Chúng tôi đã sử dụng phương pháp này, và nó đang làm việc thực sự tốt. Vào thời gian chạy, phải mất một khoảng thời gian không thể đo lường để hoàn nguyên phương thức và chạy nó.

Chỉ điều cần chú ý ... Hội đồng đã ký và Hội đồng chưa ký kết không được trộn dữ liệu phương thức được tuần tự hóa.

+0

Đây là phương pháp tôi đã đưa ra và đã được làm việc trên. Vấn đề lớn nhất dường như là chuyển đổi mảng byte mà MethodBody đưa vào OpCodes để sử dụng với Reflection.Emit. Tôi đang xem http://weblogs.asp.net/rosherove/archive/2006/04/25/methodsvisualizer.aspx có thể hữu ích. – ICR

+0

o0o điều này nghe giống như cách tiếp cận mà tôi đang tìm kiếm. Nếu bạn có thêm bất kỳ nguồn lực nào liên quan đến suy nghĩ, các liên kết sẽ được đánh giá rất cao :) – NoizWaves

+3

Tôi không thể quyết định nếu những gì bạn đã làm là tuyệt vời hoặc khủng khiếp. Có thể cả hai. – Anthony

1

Biên dịch thành một hội đồng riêng biệt, gửi hội đồng, có quá trình khác tải nó.

Bạn có thể muốn xem xét các tác động bảo mật.

Cập nhật: ý tưởng khác sẽ được tạo ra một cây biểu thức và sử dụng thư viện này để serialize nó:

http://www.codeplex.com/metalinq/

3

Bạn cũng có thể gửi nó như là một chuỗi sau đó sử dụng CodeDomProvider để biên dịch nó, cùng một kết quả. Tôi có một chút ví dụ về mã như sau:

using System; 
using System.CodeDom.Compiler; 
using System.Collections.Generic; 
using System.Collections.Specialized; 
using System.IO; 
using System.Linq; 
using System.Reflection; 
using System.Text; 
using Microsoft.CSharp; 

namespace DynamicCodeApplication 
{ 
    class azCodeCompiler 
    { 
     private List<string> assemblies; 

     public azCodeCompiler() 
     { 
      assemblies = new List<string>(); 
      scanAndCacheAssemblies(); 
     } 

     public Assembly BuildAssembly(string code) 
     { 

      CodeDomProvider prov = CodeDomProvider.CreateProvider("CSharp"); 
      string[] references = new string[] { }; // Intentionally empty, using csc.rsp 
      CompilerParameters cp = new CompilerParameters(references) 
             { 
              GenerateExecutable = false, 
              GenerateInMemory = true 
             }; 
      string path = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(); 
      cp.CompilerOptions = "@" + path + @"\csc.rsp"; 
      CompilerResults cr = prov.CompileAssemblyFromSource(cp, code); 

      foreach (CompilerError err in cr.Errors) 
      { 
       Console.WriteLine(err.ToString()); 
      } 
      return cr.CompiledAssembly; 
     } 

     public object ExecuteCode(string code, 
            string namespacename, string classname, 
            string functionname, bool isstatic, params object[] args) 
     { 
      object returnval = null; 
      Assembly asm = BuildAssembly(code); 
      object instance = null; 
      Type type = null; 
      if (isstatic) 
      { 
       type = asm.GetType(namespacename + "." + classname); 
      } 
      else 
      { 
       instance = asm.CreateInstance(namespacename + "." + classname); 
       type = instance.GetType(); 
      } 
      MethodInfo method = type.GetMethod(functionname); 
      returnval = method.Invoke(instance, args); 
      return returnval; 
     } 

     private void scanAndCacheAssemblies() 
     { 

      /* 
      foreach (string str in Directory.GetFiles(@"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727")) 
      { 
       if (str.Contains(".dll")) 
       { 
        foreach (string st in str.Split(new char[] { '\\' })) 
        { 
         if (st.Contains(".dll")) 
         { 
          assemblies.Add(st); 
         } 
        } 
       } 
      } 
      * */ 

      assemblies.Add("Accessibility.dll"); 
      assemblies.Add("AspNetMMCExt.dll"); 
      assemblies.Add("cscompmgd.dll"); 
      assemblies.Add("CustomMarshalers.dll"); 
      assemblies.Add("IEExecRemote.dll"); 
      assemblies.Add("IEHost.dll"); 
      assemblies.Add("IIEHost.dll"); 
      assemblies.Add("Microsoft.Build.Conversion.dll"); 
      assemblies.Add("Microsoft.Build.Engine.dll"); 
      assemblies.Add("Microsoft.Build.Framework.dll"); 
      assemblies.Add("Microsoft.Build.Tasks.dll"); 
      assemblies.Add("Microsoft.Build.Utilities.dll"); 
      assemblies.Add("Microsoft.Build.VisualJSharp.dll"); 
      assemblies.Add("Microsoft.CompactFramework.Build.Tasks.dll"); 
      assemblies.Add("Microsoft.JScript.dll"); 
      assemblies.Add("Microsoft.VisualBasic.Compatibility.Data.dll"); 
      assemblies.Add("Microsoft.VisualBasic.Compatibility.dll"); 
      assemblies.Add("Microsoft.VisualBasic.dll"); 
      assemblies.Add("Microsoft.VisualBasic.Vsa.dll"); 
      assemblies.Add("Microsoft.Vsa.dll"); 
      assemblies.Add("Microsoft.Vsa.Vb.CodeDOMProcessor.dll"); 
      assemblies.Add("Microsoft_VsaVb.dll"); 
      assemblies.Add("mscorlib.dll"); 
      assemblies.Add("sysglobl.dll"); 
      assemblies.Add("System.configuration.dll"); 
      assemblies.Add("System.Configuration.Install.dll"); 
      assemblies.Add("System.Data.dll"); 
      assemblies.Add("System.Data.OracleClient.dll"); 
      assemblies.Add("System.Data.SqlXml.dll"); 
      assemblies.Add("System.Deployment.dll"); 
      assemblies.Add("System.Design.dll"); 
      assemblies.Add("System.DirectoryServices.dll"); 
      assemblies.Add("System.DirectoryServices.Protocols.dll"); 
      assemblies.Add("System.dll"); 
      assemblies.Add("System.Drawing.Design.dll"); 
      assemblies.Add("System.Drawing.dll"); 
      assemblies.Add("System.EnterpriseServices.dll"); 
      assemblies.Add("System.Management.dll"); 
      assemblies.Add("System.Messaging.dll"); 
      assemblies.Add("System.Runtime.Remoting.dll"); 
      assemblies.Add("System.Runtime.Serialization.Formatters.Soap.dll"); 
      assemblies.Add("System.Security.dll"); 
      assemblies.Add("System.ServiceProcess.dll"); 
      assemblies.Add("System.Transactions.dll"); 
      assemblies.Add("System.Web.dll"); 
      assemblies.Add("System.Web.Mobile.dll"); 
      assemblies.Add("System.Web.RegularExpressions.dll"); 
      assemblies.Add("System.Web.Services.dll"); 
      assemblies.Add("System.Windows.Forms.dll"); 
      assemblies.Add("System.XML.dll"); 
      assemblies.Add("vjscor.dll"); 
      assemblies.Add("vjsjbc.dll"); 
      assemblies.Add("vjslib.dll"); 
      assemblies.Add("vjslibcw.dll"); 
      assemblies.Add("vjssupuilib.dll"); 
      assemblies.Add("vjsvwaux.dll"); 
      assemblies.Add("vjswfc.dll"); 
      assemblies.Add("VJSWfcBrowserStubLib.dll"); 
      assemblies.Add("vjswfccw.dll"); 
      assemblies.Add("vjswfchtml.dll"); 
      assemblies.Add("Accessibility.dll"); 
      assemblies.Add("AspNetMMCExt.dll"); 
      assemblies.Add("cscompmgd.dll"); 
      assemblies.Add("CustomMarshalers.dll"); 
      assemblies.Add("IEExecRemote.dll"); 
      assemblies.Add("IEHost.dll"); 
      assemblies.Add("IIEHost.dll"); 
      assemblies.Add("Microsoft.Build.Conversion.dll"); 
      assemblies.Add("Microsoft.Build.Engine.dll"); 
      assemblies.Add("Microsoft.Build.Framework.dll"); 
      assemblies.Add("Microsoft.Build.Tasks.dll"); 
      assemblies.Add("Microsoft.Build.Utilities.dll"); 
      assemblies.Add("Microsoft.Build.VisualJSharp.dll"); 
      assemblies.Add("Microsoft.CompactFramework.Build.Tasks.dll"); 
      assemblies.Add("Microsoft.JScript.dll"); 
      assemblies.Add("Microsoft.VisualBasic.Compatibility.Data.dll"); 
      assemblies.Add("Microsoft.VisualBasic.Compatibility.dll"); 
      assemblies.Add("Microsoft.VisualBasic.dll"); 
      assemblies.Add("Microsoft.VisualBasic.Vsa.dll"); 
      assemblies.Add("Microsoft.Vsa.dll"); 
      assemblies.Add("Microsoft.Vsa.Vb.CodeDOMProcessor.dll"); 
      assemblies.Add("Microsoft_VsaVb.dll"); 
      assemblies.Add("mscorlib.dll"); 
      assemblies.Add("sysglobl.dll"); 
      assemblies.Add("System.configuration.dll"); 
      assemblies.Add("System.Configuration.Install.dll"); 
      assemblies.Add("System.Data.dll"); 
      assemblies.Add("System.Data.OracleClient.dll"); 
      assemblies.Add("System.Data.SqlXml.dll"); 
      assemblies.Add("System.Deployment.dll"); 
      assemblies.Add("System.Design.dll"); 
      assemblies.Add("System.DirectoryServices.dll"); 
      assemblies.Add("System.DirectoryServices.Protocols.dll"); 
      assemblies.Add("System.dll"); 
      assemblies.Add("System.Drawing.Design.dll"); 
      assemblies.Add("System.Drawing.dll"); 
      assemblies.Add("System.EnterpriseServices.dll"); 
      assemblies.Add("System.Management.dll"); 
      assemblies.Add("System.Messaging.dll"); 
      assemblies.Add("System.Runtime.Remoting.dll"); 
      assemblies.Add("System.Runtime.Serialization.Formatters.Soap.dll"); 
      assemblies.Add("System.Security.dll"); 
      assemblies.Add("System.ServiceProcess.dll"); 
      assemblies.Add("System.Transactions.dll"); 
      assemblies.Add("System.Web.dll"); 
      assemblies.Add("System.Web.Mobile.dll"); 
      assemblies.Add("System.Web.RegularExpressions.dll"); 
      assemblies.Add("System.Web.Services.dll"); 
      assemblies.Add("System.Windows.Forms.dll"); 
      assemblies.Add("System.XML.dll"); 
      assemblies.Add("vjscor.dll"); 
      assemblies.Add("vjsjbc.dll"); 
      assemblies.Add("vjslib.dll"); 
      assemblies.Add("vjslibcw.dll"); 
      assemblies.Add("vjssupuilib.dll"); 
      assemblies.Add("vjsvwaux.dll"); 
      assemblies.Add("vjswfc.dll"); 
      assemblies.Add("VJSWfcBrowserStubLib.dll"); 
      assemblies.Add("vjswfccw.dll"); 
      assemblies.Add("vjswfchtml.dll"); 


      return; 
     } 
    } 
} 
+0

Đó sẽ là một trợ giúp tuyệt vời Tarks, cảm ơn! Tiếp tục theo chủ đề này, có thể biến một khối mã C# thành chuỗi không? – NoizWaves

0

Một lựa chọn khác là sử dụng DLR, và kìm hãm mã để thực hiện ...

4

Nói chung mà âm thanh như một ý tưởng thực sự tồi tệ và một lỗ hổng bảo mật lớn .

Bạn không muốn quy trình khác thực thi bất kỳ mã nào. Hiểu những gì bạn thực sự cần một quá trình khác để làm và xây dựng một DSL nhỏ xung quanh nó.

+0

Tuyệt đối, bạn không thể tin tưởng người gọi mà bạn thực sự muốn đưa ra một DSL. Hãy xem MGrammar và Oslo. –

+0

Thực thi mã tùy ý và/hoặc lưu trữ nó trong cơ sở dữ liệu ở đâu đó ... điều gì có thể xảy ra sai? Không có vẻ như một anti-pattern với tôi ;-) –

7

Bạn có thể thử sử dụng IronPython trong dự án của mình. Đó là trivial để thực hiện những gì bạn đang yêu cầu bằng Python. Mã Python có thể gọi các phương thức C# của bạn. Đối với bảo mật, bạn có thể thực thi mã trong môi trường bị hạn chế của một số loại (ví dụ: RestrictedPython).

1

Đây là một thử thách thú vị, nhưng bạn có lẽ nên mô tả lý do tại sao bạn muốn làm điều này, vì có rất nhiều cách tiếp cận khác nhau tùy thuộc vào mục tiêu của bạn. Như humpohl chỉ ra, đó cũng là một số vấn đề an ninh khá nghiêm trọng.

"Mã được tuần tự hóa" chỉ có thể là mã nguồn hoặc một bộ sưu tập được biên dịch, tùy thuộc vào yêu cầu của bạn. Có thể bạn không cần sử dụng định dạng tuần tự mã riêng biệt.

Nếu bạn muốn tạo mã động và chuyển mã đó vào, bạn có thể tạo mã bằng CodeDOM và biên dịch mã đó. Tuy nhiên, bạn rất có thể không cần phải tạo mã hoàn toàn tùy ý.

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