C# 如何在字节数组中序列化/反序列化程序集对象

C# 如何在字节数组中序列化/反序列化程序集对象,c#,serialization,deserialization,system.reflection,C#,Serialization,Deserialization,System.reflection,让我们假设一个用户通过以下方式在内存中创建一个(可执行)程序集: 编译代码字符串。然后我想序列化这个程序集 对象转换为字节数组,然后将其存储在数据库中。后来 在上,我想从数据库中检索字节数组并反序列化 将字节数组返回到程序集对象中,然后调用该项 装配点 起初,我只是试着像处理.net中的任何其他简单对象一样进行序列化,但显然这对汇编对象不起作用。assembly对象包含一个名为GetObjectData的方法,该方法获取重新实例化程序集所需的序列化数据。所以我有点困惑,我该如何将所有这些整合到我

让我们假设一个用户通过以下方式在内存中创建一个(可执行)程序集: 编译代码字符串。然后我想序列化这个程序集 对象转换为字节数组,然后将其存储在数据库中。后来 在上,我想从数据库中检索字节数组并反序列化 将字节数组返回到程序集对象中,然后调用该项 装配点

起初,我只是试着像处理.net中的任何其他简单对象一样进行序列化,但显然这对汇编对象不起作用。assembly对象包含一个名为GetObjectData的方法,该方法获取重新实例化程序集所需的序列化数据。所以我有点困惑,我该如何将所有这些整合到我的场景中


答案只需要说明如何获取程序集对象,将其转换为字节数组,将其转换回程序集,然后在反序列化程序集上执行entry方法。

程序集更方便地表示为二进制dll文件。如果你这样想,剩下的问题就消失了。特别是,查看
Assembly.Load(byte[])
从二进制文件加载
程序集。要将其写入二进制文件,请使用并查看结果的-then
文件.ReadAllBytes(path)
,以从文件中获取二进制文件。

系统.Reflection.Assembly
可实现ISerializable
,并且可以像这样简单地序列化:

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

反序列化也同样简单,但调用BinaryFormatter。反序列化。

使用反射获取程序集字节的肮脏技巧:

  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”,它返回程序集字节。

以下是我的示例:

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));" +
      "         }" +
      "     }" +
      " }" +
      "}";
    }
公共静态字节[]序列化程序集()
{
var compilerOptions=新字典{{“CompilerVersion”,“v4.0”};
CSharpCodeProvider provider=新的CSharpCodeProvider(编译器选项);
CompilerParameters参数=新的CompilerParameters()
{
GenerateExecutable=false,
GenerateInMemory=false,
OutputAssembly=“Examples.dll”,
IncludeDebugInformation=false,
};
parameters.referencedAssembly.Add(“System.dll”);
ICodeCompiler compiler=provider.CreateCompiler();
CompilerResults results=compiler.compileAsemblyFromSource(参数,StringClassFile());
返回File.ReadAllBytes(results.CompiledAssembly.Location);
}
私有静态程序集反序列化Assembyl(DataReader中的对象)
{
字节[]arr=(字节[])来自DataReader;
返回组件。负载(arr);
}
私有字符串StringClassFile()
{
返回“使用系统”+
“使用System.IO;”+
“使用系统线程;”+
“名称空间示例”+
"{" +
“公共类FileCreator”+
" {" +
“私有字符串FolderPath{get;set;}”+
“公共文件创建者(字符串folderPath)”+
"     {" +
“this.FolderPath=FolderPath;”+
"     }" +
“公共无效创建文件(Guid名称)”+
"     {" +
字符串文件名=string.Format(\“{0}.txt\”,name.ToString())+
字符串路径=path.Combine(this.FolderPath,文件名)+
“如果(!File.Exists(path))”+
"         {" +
“使用(StreamWriter sw=File.CreateText(路径))”+
"             {" +
sw.WriteLine(\“文件:{0}\”,文件名)+
sw.WriteLine(\“从线程id:{0}\”创建,thread.CurrentThread.ManagedThreadId)+
"             }" +
"         }" +
“其他”+
"         {" +
抛出新异常(string.Format(\“找到重复文件{0}\”,文件名))+
"         }" +
"     }" +
" }" +
"}";
}

但是如果你完全在内存中编译怎么办?@bicker那么这是一种痛苦;p除了“这里编译到临时文件夹会更容易”之外,我没有直接的答案。如果一周内没有人在内存中找到答案,那么我会将其标记为答案。反序列化它将不会生成相同的程序集。。。换句话说,您创建的内存流的大小不等于程序集文件的大小。@TonoNam可能不等于,但他们特别询问了如何序列化对象,这可以做到。这并不一定意味着它将是程序员所期望的。虽然我想测试和验证您的语句,但我认为它应该生成功能相同的assembly.System.Reflection.assembly实现System.Runtime.Serialization.ISerializable接口,并在其GetObjectData方法中序列化其FullName属性。反序列化时,它将从程序集的全名加载程序集,以便对appdomain已知的程序集进行序列化和反序列化时,它可以工作,但不是“序列化程序集解决方案”。GetRawBytes不再存在于较新的.net版本中()