簡體   English   中英

如何將程序集對象序列化/反序列化到字節數組或從字節數組反序列化

[英]how to serialize/deserialize an assembly object to and from a byte array

假設通過編譯代碼字符串在內存中創建(可執行)程序集。 然后我想將這個程序集對象序列化為一個字節數組,然后將其存儲在數據庫中。 然后我想從數據庫中檢索字節數組並將字節數組反序列化回程序集對象,然后調用程序集的入口點。

起初,我只是嘗試像處理 .net 中的任何其他簡單對象一樣執行此序列化,但顯然這不適用於程序集對象。 程序集對象包含一個名為 GetObjectData 的方法,該方法獲取重新實例化程序集所需的序列化數據。 所以我對如何將所有這些拼湊成我的場景有些困惑。

答案只需要展示如何獲取程序集對象,將其轉換為字節數組,將其轉換回程序集,然后在反序列化的程序集上執行入口方法。

使用反射獲取程序集字節的骯臟技巧:

  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)從文件中獲取二進制文件。

這是我的例子:

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

System.Reflection.AssemblyISerializable並且可以像這樣簡單地序列化:

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

和反序列化同樣簡單,但調用BinaryFormatter.Deserialize代替。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM