是否可以序列化C#代码块?

我正在使用C#和.NET 3.5。 是否可以序列化代码块,将其传输到某处,对其进行反序列化,然后执行它?

一个示例用法是:

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

有些远程程序在做:

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

我的最终目标是能够在不同的进程中执行任意代码(它没有代码的先验知识)。

是!!!

我们这样做是为了一个非常真实的表现。 由于性能原因,在运行时或使用DSL执行此操作不是一种选择。

我们将代码编译成程序集,并将IL从方法中删除。 然后,我们获取与此方法相关的所有元数据,并通过XML序列化整个混乱,压缩它,并将其放入我们的数据库中。

在重新水化时,我们使用DynamicMethod类重新构造 IL和元数据,并执行它。

我们这样做是因为速度快。 我们有成千上万的小代码块。 不幸的是,编译一段代码并在运行中运行它需要至少250毫秒,这对我们来说太慢了。 我们采用了这种方法,它的工作非常好。 在运行时,重新构建方法并运行它需要不可测量的时间。

唯一值得关注的是……签名的程序集和无符号程序集不能混合序列化的方法数据。

您可以尝试在项目中使用IronPython 。 在Python中做你要求的事情是微不足道的 。 Python代码可以调用您的C#方法。 至于安全性,您可以在某种受限制的环境中执行代码(例如RestrictedPython )。

一般来说,这听起来像一个非常糟糕的主意和一个很大的安全漏洞。

您不希望其他进程执行任何代码。 了解您真正需要另一个流程来做什么,并围绕它构建一个小型DSL。

您也可以将其作为字符串发送,然后使用CodeDomProvider进行编译,结果相同。 我有一个代码示例:

 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 assemblies; public azCodeCompiler() { assemblies = new List(); 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; } } } 

将其编译为单独的程序集,发送程序集,让其他进程加载它。

您可能想要考虑安全隐患。

更新:另一个想法是生成表达式树并使用此库来序列化它:

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

这是一个有趣的挑战,但您应该描述为什么要这样做,因为根据您的目标有很多不同的方法。 正如humpohl指出的那样,还有一些非常严重的安全问题。

“序列化代码”可能只是源代码或编译程序集,具体取决于您的要求。 您可能不需要使用单独的代码序列化格式。

如果要动态生成代码并将其传递,可以使用CodeDOM生成代码并进行编译。 但是,您很可能不需要生成完全任意的代码。

另一个选择是使用DLR ,并限制代码执行…