我正在尝试让BinaryFormatter
在我的程序集的不同版本中工作。我希望反序列化的实际类在每个程序集版本中完全相同,但在反序列化时,因为序列化对象包括它们来自的程序集名称,BinaryFormatter
抱怨它找不到正确的部件。所以我创建了一个自定义SerializationBinder
,告诉BinaryFormatter
始终反序列化到当前的程序集版本。
我的方案可以正常反序列化对象,但是如果我的对象是T的List,它就不起作用,其中T是从我的程序集的旧版本序列化的类型。
有没有办法让这个工作与Lists和其他泛型类型一起使用,其中type参数是我的程序集中的一个类?
//the object i want to deserialize
class MyObject
{
public string Name{get;set;}
}
//my binder class
class MyBinder : SerializationBinder
{
static string assemblyToUse = typeof (MyObject).Assembly.FullName;
public override Type BindToType(string assemblyName, string typeName)
{
var isMyAssembly = assemblyName.StartsWith("oldAssemblyName");
var assemblyNameToUse = isMyAssembly ? assemblyToUse : assemblyName;
var tn = typeName + ", " + assemblyNameToUse;
return Type.GetType(tn);
}
}
//my deserialize method
static object BinaryDeserialize(string input)
{
var arr = Convert.FromBase64String(input);
var ms = new MemoryStream(arr);
ms.Seek(0, SeekOrigin.Begin);
var bf = new BinaryFormatter();
bf.Binder = new MyBinder();
var obj = bf.Deserialize(ms);
return obj;
}
static void Test()
{
//this works
//serialized(new MyObject());
var str = ReadSerialized_MyObject();
var obj = BinaryDeserialize(str);
//this doesn't work
//serialized(new List<MyObject>());
var str2 = ReadSerialized_List_of_MyObject();
var obj = BinaryDeserialize(str2);
}
答案 0 :(得分:7)
如果您序列化List&lt;的实例MyClass&gt;从您的1.0.0.0版本程序集中,将要求SerializationBinder.BindToType函数提供此类型:
System.Collections.Generic.List`1[[MyAssembly.MyClass, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=12345678901234567890]]
为了重新映射List&lt; MyClass&gt;键入您的版本2.0.0.0程序集,您需要将类型名称更改为:
System.Collections.Generic.List`1[[MyAssembly.MyClass, MyAssembly]]
需要注意的要点是,程序集名称不是完全限定的。如果您尝试使用2.0.0.0版本号完全限定程序集名称,则它将无效。
答案 1 :(得分:1)
应用程序A创建一个序列化二进制格式化程序文件“SerializedList.bin”,其中包含List(Result),其中Result是Serializable对象。 现在,应用程序B想要对文件进行DeSerialize并加载到List(Result)对象中。 这就是我如何运作..
应用程序A程序集名称为“Serialize”
应用程序B程序集名称为“DeSerialize”
应用程序代码(序列化):
namespace Serialize
{
class Program
{
static void Main(string[] args)
{
List<Result> result = ;//Get From DB
IFormatter formatter = new BinaryFormatter();
Stream sStream = new FileStream(
"SerializedList.bin",
FileMode.CreateNew,
FileAccess.Write,
FileShare.None);
formatter.Serialize(sStream, result);
sStream.Close();
}
}
}
一些结果对象:
[Serializable]
public class Result
{
public decimal CONTACT_ID { get; set; }
public decimal INSTITUTION_NBR { get; set; }
}
申请B代码(DeSerialize):
namespace DeSerialize
{
class Program
{
static void Main(string[] args)
{
IFormatter formatter = new BinaryFormatter();
string fromTypeName = "System.Collections.Generic.List`1[[Serialize.Result, Serialize, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]";
string fromTypeName1 = "Serialize.Result";
string toTypename = "System.Collections.Generic.List`1[DeSerialize.Result]";
string toTypename1 = "DeSerialize.Result";
string toTypeAssemblyName = Assembly.GetExecutingAssembly().FullName;
DictionarySerializationBinder dic = new DictionarySerializationBinder();
dic.AddBinding(fromTypeName, toTypename);
dic.AddAssemblyQualifiedTypeBinding(fromTypeName1, toTypename1, toTypeAssemblyName);
formatter.Binder = dic;
Stream dStream = new FileStream(
"SerializeList.bin",
FileMode.Open,
FileAccess.Read,
FileShare.Read);
List<Result> listDS =
(List<Result>)formatter.Deserialize(dStream);
dStream.Close();
}
}
sealed class DictionarySerializationBinder : SerializationBinder
{
Dictionary<string, Type> _typeDictionary = new Dictionary<string, Type>();
public override Type BindToType(string assemblyName, string typeName)
{
Type typeToReturn;
if (_typeDictionary.TryGetValue(typeName, out typeToReturn))
{
return typeToReturn;
}
else
{
return null;
}
}
public void AddBinding(string fromTypeName, string toTypeName)
{
Type toType = Type.GetType(toTypeName);
if (toType == null)
{
throw new ArgumentException(string.Format(
"Help, I could not convert '{0}' to a valid type.", toTypeName));
}
_typeDictionary.Add(fromTypeName, toType);
}
public void AddAssemblyQualifiedTypeBinding(string fromTypeName, string toTypeName, string toTypeAssemblyName)
{
Type typeToSerializeTo = GetAssemblyQualifiedType(toTypeAssemblyName, toTypeName);
if (typeToSerializeTo == null)
{
throw new ArgumentException(string.Format(
"Help, I could not convert '{0}' to a valid type.", toTypeName));
}
_typeDictionary.Add(fromTypeName, typeToSerializeTo);
}
private static Type GetAssemblyQualifiedType(string assemblyName, string typeName)
{
return Type.GetType(String.Format("{0}, {1}", typeName, assemblyName));
}
}
}
答案 2 :(得分:0)
只需处理AppDomain.AssemblyResolve
事件并在调用Type.GetType
方法时返回所需的程序集。就是这么简单!
答案 3 :(得分:0)
您还可以在BindToType函数中使用更简单的构造:
var tn = typeof(List<MyClass>).AssemblyQualifiedName;
return Type.GetType(tn, true)
如果您的类型定义不正确,最后一个参数'true'将给您错误消息(带有跟踪)。这样可以节省您以后的调试时间。