如何将程序集对象与字节数组进行序列化/反序列化

本文关键字:数组 序列化 反序列化 字节数 字节 程序集 对象 | 更新日期: 2023-09-27 18:10:11

假设在内存中创建一个(可执行的)程序集编译代码字符串。然后我要序列化这个程序集对象放入字节数组,然后将其存储在数据库中。之后我想从数据库中检索字节数组并进行反序列化将字节数组返回到程序集对象中,然后调用该项装配点

起初,我只是试图做这个序列化,就像我在。net中做任何其他简单对象一样,但显然这不会与汇编对象一起工作。程序集对象包含一个名为GetObjectData的方法,该方法获取重新实例化程序集所需的序列化数据。所以我有点困惑,我如何把所有这些拼凑在一起,为我的场景。

答案只需要显示如何获取一个汇编对象,将其转换为字节数组,再将其转换回一个汇编,然后在反序列化的汇编上执行entry方法。

如何将程序集对象与字节数组进行序列化/反序列化

使用反射获取汇编字节的肮脏技巧:

  MethodInfo methodGetRawBytes = assembly.GetType().GetMethod("GetRawBytes", BindingFlags.Instance | BindingFlags.NonPublic);
  object o = methodGetRawBytes.Invoke(assembly, null);
  
  byte[] assemblyBytes = (byte[])o;

解释:至少在我的示例中(程序集是从字节数组加载的),程序集实例的类型是"System.Reflection.RuntimeAssembly"这是一个内部类,因此只能使用反射来访问它。"RuntimeAssembly"有一个方法GetRawBytes"它返回程序集字节。

程序集更方便地表示为二进制dll文件。如果你像那样思考,其他的问题就会消失。特别是,查看Assembly.Load(byte[])从二进制文件加载Assembly。要写入二进制文件,请使用CompileAssemblyFromSource并查看结果的PathToAssembly -然后使用File.ReadAllBytes(path)从文件中获取二进制文件

System.Reflection.AssemblyISerializable,可以简单地像这样序列化:

Assembly asm = Assembly.GetExecutingAssembly();
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, asm);

和反序列化同样简单,但要调用BinaryFormatter.Deserialize

下面是我的例子:

public static byte[] SerializeAssembly()
{
  var compilerOptions = new Dictionary<string, string> { { "CompilerVersion", "v4.0" } };
  CSharpCodeProvider provider = new CSharpCodeProvider(compilerOptions);
  CompilerParameters parameters = new CompilerParameters()
  {
    GenerateExecutable = false,
    GenerateInMemory = false,
    OutputAssembly = "Examples.dll",
    IncludeDebugInformation = false,
  };
  parameters.ReferencedAssemblies.Add("System.dll");
  ICodeCompiler compiler = provider.CreateCompiler();
  CompilerResults results = compiler.CompileAssemblyFromSource(parameters, StringClassFile());
  return File.ReadAllBytes(results.CompiledAssembly.Location);
}
private static Assembly DeserializeAssembyl(object fromDataReader)
{
  byte[] arr = (byte[])fromDataReader;
  return Assembly.Load(arr);
}

private string StringClassFile()
    {
      return "using System;" +
      "using System.IO;" +
      "using System.Threading;" +
      "namespace Examples" +
      "{" +
      " public class FileCreator" +
      " {" +
      "     private string FolderPath { get; set; }" +
      "     public FileCreator(string folderPath)" +
      "     {" +
      "         this.FolderPath = folderPath;" +
      "     }" +
      "     public void CreateFile(Guid name)" +
      "     {" +
      "         string fileName = string.Format('"{0}.txt'", name.ToString());" +
      "         string path = Path.Combine(this.FolderPath, fileName);" +
      "         if (!File.Exists(path))" +
      "         {" +
      "             using (StreamWriter sw = File.CreateText(path))" +
      "             {" +
      "                 sw.WriteLine('"file: {0}'", fileName);" +
      "                 sw.WriteLine('"Created from thread id: {0}'", Thread.CurrentThread.ManagedThreadId);" +
      "             }" +
      "         }" +
      "         else" +
      "         {" +
      "             throw new Exception(string.Format('"duplicated file found {0}'", fileName));" +
      "         }" +
      "     }" +
      " }" +
      "}";
    }