如何将程序集对象序列化到字节数组或从字节数组反序列化

发布于 2024-12-07 16:52:07 字数 321 浏览 4 评论 0原文

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

起初,我只是尝试像 .net 中的任何其他简单对象一样进行序列化,但显然这不适用于程序集对象。程序集对象包含一个名为 GetObjectData 的方法,该方法获取重新实例化程序集所需的序列化数据。所以我对如何将所有这些拼凑起来以适应我的场景感到有些困惑。

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

Let's say a create an (executable) assembly in memory by
compiling a code string. Then I want to serialize this assembly
object into a byte array and then store it in a database. Then later
on I want to retrieve the byte array from the database and deserialize
the byte array back into an assembly object, then invoke the entry
point of the assembly.

At first I just tried to do this serialization like I would any other simple object in .net, however apparently that won't work with an assembly object. The assembly object contains a method called GetObjectData which gets serialization data necessary to reinstantiate the assembly. So I'm somewhat confused as to how I piece all this together for my scenario.

The answer only needs to show how to take an assembly object, convert it into a byte array, convert that back into an assembly, then execute the entry method on the deserialized assembly.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

隱形的亼 2024-12-14 16:52:07

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

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

A dirty trick to get the assembly bytes using reflection:

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

Explanation: at least in my sample (assembly was loaded from byte array) the assembly instance was of type "System.Reflection.RuntimeAssembly". This is an internal class, so it can be accessed only using reflection. "RuntimeAssembly" has a method "GetRawBytes", which return the assembly bytes.

剧终人散尽 2024-12-14 16:52:07

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

An assembly is more conveniently represented simply as a binary dll file. If you think of it like that, the rest of the problems evaporate. In particlar, look at Assembly.Load(byte[]) for loading an Assembly from binary. To write it as binary, use CompileAssemblyFromSource and look at the result's PathToAssembly - then File.ReadAllBytes(path) to obtain the binary from the file.

依 靠 2024-12-14 16:52:07

这是我的例子:

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));" +
      "         }" +
      "     }" +
      " }" +
      "}";
    }

Here is my example:

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));" +
      "         }" +
      "     }" +
      " }" +
      "}";
    }
与酒说心事 2024-12-14 16:52:07

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

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

反序列化也同样简单,但改为调用 BinaryFormatter.Deserialize。

System.Reflection.Assembly is ISerializable and can simply be serialized like so:

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

and deserialization is just as simple but call BinaryFormatter.Deserialize instead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文