Mik*_*ark 12 c# ilmerge binary-serialization
我有一个带有引用的dll的C#解决方案(也是具有相同.Net版本的C#).当我构建解决方案并运行生成的exe,而不合并exe和引用的DLL时,一切正常.
现在我想将这些合并到一个exe中.我运行ILMerge,一切似乎都正常.我尝试执行exe,它似乎运行正常,直到它尝试反序列化引用的DLL中定义的对象.
using (Stream fstream = new FileStream(file_path, FileMode.Open))
{
BinaryFormatter bf = new BinaryFormatter();
return bf.Deserialize(fstream) as ControlledRuleCollection;
// throws unable to find assembly exception
}
Run Code Online (Sandbox Code Playgroud)
可能有一些ILMerge选项我在这里丢失了吗?
小智 38
您可以通过创建和添加SerializationBinder子类来完成此操作,该子类将在反序列化发生之前更改程序集名称.
sealed class PreMergeToMergedDeserializationBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type typeToDeserialize = null;
// For each assemblyName/typeName that you want to deserialize to
// a different type, set typeToDeserialize to the desired type.
String exeAssembly = Assembly.GetExecutingAssembly().FullName;
// The following line of code returns the type.
typeToDeserialize = Type.GetType(String.Format("{0}, {1}",
typeName, exeAssembly));
return typeToDeserialize;
}
}
Run Code Online (Sandbox Code Playgroud)
然后在反序列化时将其添加到BinaryFormatter:
BinaryFormatter bf = new BinaryFormatter();
bf.Binder = new PreMergeToMergedDeserializationBinder();
object obj = bf.Deserialize(ms);
Run Code Online (Sandbox Code Playgroud)
听起来你已经在DLL中序列化了一个对象,然后将所有程序集与ILMerge合并,现在正在尝试反序列化该对象.这根本行不通.二进制序列化的反序列化过程将尝试从原始DLL加载对象的类型.ILMerge后不存在此DLL,因此反序列化将失败.
序列化和反序列化过程需要在合并前或合并后进行操作.它不能混合
SerializationBinder也是我的解决方案。但是我在被引用的DLL中有该类。因此,我必须在所有负载组件中进行搜索。如果活页夹应该在dll中搜索,我已经修改了带有参数的答案。
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace ibKastl.Helper
{
public static class BinaryFormatterHelper
{
public static T Read<T>(string filename, Assembly currentAssembly)
{
T retunValue;
FileStream fileStream = new FileStream(filename, FileMode.Open);
try
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Binder = new SearchAssembliesBinder(currentAssembly,true);
retunValue = (T)binaryFormatter.Deserialize(fileStream);
}
finally
{
fileStream.Close();
}
return retunValue;
}
public static void Write<T>(T obj, string filename)
{
FileStream fileStream = new FileStream(filename, FileMode.Create);
BinaryFormatter formatter = new BinaryFormatter();
try
{
formatter.Serialize(fileStream, obj);
}
finally
{
fileStream.Close();
}
}
}
sealed class SearchAssembliesBinder : SerializationBinder
{
private readonly bool _searchInDlls;
private readonly Assembly _currentAssembly;
public SearchAssembliesBinder(Assembly currentAssembly, bool searchInDlls)
{
_currentAssembly = currentAssembly;
_searchInDlls = searchInDlls;
}
public override Type BindToType(string assemblyName, string typeName)
{
List<AssemblyName> assemblyNames = new List<AssemblyName>();
assemblyNames.Add(_currentAssembly.GetName()); // EXE
if (_searchInDlls)
{
assemblyNames.AddRange(_currentAssembly.GetReferencedAssemblies()); // DLLs
}
foreach (AssemblyName an in assemblyNames)
{
var typeToDeserialize = GetTypeToDeserialize(typeName, an);
if (typeToDeserialize != null)
{
return typeToDeserialize; // found
}
}
return null; // not found
}
private static Type GetTypeToDeserialize(string typeName, AssemblyName an)
{
string fullTypeName = string.Format("{0}, {1}", typeName, an.FullName);
var typeToDeserialize = Type.GetType(fullTypeName);
return typeToDeserialize;
}
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
const string FILENAME = @"MyObject.dat";
// Serialize
BinaryFormatterHelper.Write(myObject1,FILENAME);
// Deserialize
MyObject myObject2 = BinaryFormatterHelper.Read<MyObject>(FILENAME, Assembly.GetExecutingAssembly()); // Current Assembly where the dll is referenced
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
20107 次 |
| 最近记录: |