[英]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.Assembly
是ISerializable
并且可以像这样简单地序列化:
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.