【问题标题】:Is it possible to serialize a C# code block?是否可以序列化 C# 代码块?
【发布时间】:2026-02-07 20:40:01
【问题描述】:

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

这个例子的用法是:

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

有一些远程程序在做:

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

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

【问题讨论】:

  • 当一个客户每天必须从几百个来源处理数千个文件导入时,我创建了一个通用导入工具,允许高级用户定义文件列并输入一行C# 将输入值转换为适当的类型/格式。保存新定义后,我们将为此源动态编译导入类,然后在新文件到达时执行它。它可以自动完成 50 个左右的常见案例,它运行得非常好,节省了大量的更改请求,并将导入速度提高了一个数量级。

标签: c# serialization


【解决方案1】:

是的!!!

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

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

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

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

唯一需要注意的...有符号程序集和无符号程序集不能混合序列化的方法数据。

【讨论】:

  • 这是我想出并一直在努力的方法。最大的问题似乎是将 MethodBody 提供的字节数组转换为 OpCodes 以与 Reflection.Emit 一起使用。我正在查看weblogs.asp.net/rosherove/archive/2006/04/25/…,这可能会有所帮助。
  • o0o 这听起来像是我正在寻找的方法。如果您有更多与思考相关的资源,我们将非常感谢您提供链接:)
  • 我无法确定你所做的事情是惊人的还是糟糕的。可能两者兼而有之。
  • blogs.msdn.com/haibo_luo/archive/2006/11/07/… 似乎也很有用,也许更有用。
  • 惊人还是糟糕?我认为两者兼而有之。我真的无能为力,只能认为这是一个巨大的黑客攻击......当它最终奏效时,我感到很惊讶......对解决方案的真正邪恶/复杂程度感到震惊。
【解决方案2】:

您可以尝试在您的项目中使用IronPythontrivial 在 Python 中执行您所要求的操作。 Python 代码可以调用您的 C# 方法。至于安全性,您可以在某种受限环境中执行代码(例如RestrictedPython)。

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 当然,你不能相信你真正想出 DSL 的调用者。看看 MGrammar 和 Oslo。
    • 执行任意代码和/或将其存储在数据库中的某处......可能会出现什么问题?对我来说,这似乎不是一种反模式;-)
    【解决方案4】:

    您也可以将其作为字符串发送,然后使用 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<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;
            }
        }
    }
    

    【讨论】:

    • 那将是一个很大的帮助塔克斯,谢谢!继续这个话题,是否可以将 c# 代码块转换为字符串?
    【解决方案5】:

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

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

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

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

    【讨论】:

      【解决方案6】:

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

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

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

      【讨论】:

        【解决方案7】:

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

        【讨论】:

          最近更新 更多