Mar*_*ark 9 .net c# serialization backwards-compatibility binary-serialization
背景如下
这个问题的解决方案是SerializationBinder,它允许我在某种意义上从一种类型"重定向"到另一种类型.
因此,我想创建一个SerializationBinder来满足这种需求.但是,它必须满足以下要求
这可能还是我在做梦?那里有什么东西已经做到了吗?我认为这是一个常见的问题.
到目前为止,我认为没有简单的方法可以做到3而且完全不做4.
这是一次尝试
public class SmartDeserializationBinder : SerializationBinder
{
/// <summary>
/// Private class to handle storing type mappings
/// </summary>
private class TypeMapping
{
public string OldAssemblyName { get; set; }
public string OldTypeName { get; set; }
public string NewAssemblyName { get; set; }
public string NewTypeName { get; set; }
}
List<TypeMapping> typeMappings;
public SmartDeserializationBinder()
{
typeMappings = new List<TypeMapping>();
}
public void AddTypeMapping(string oldAssemblyName, string oldTypeName, string newAssemblyName, string newTypeName)
{
typeMappings.Add(new TypeMapping()
{
OldAssemblyName = oldAssemblyName,
OldTypeName = oldTypeName,
NewAssemblyName = newAssemblyName,
NewTypeName = newTypeName
});
}
public override Type BindToType(string assemblyName, string typeName)
{
//Need to handle the fact that assemblyName will come in with version while input type mapping may not
//Need to handle the fact that generics come in as mscorlib assembly as opposed to the assembly where the type is defined.
//Need to handle the fact that some types won't even be defined by mapping. In this case we should revert to normal Binding... how do you do that?
string alternateAssembly = null;
string alternateTypeName = null;
bool needToMap = false;
foreach (TypeMapping mapping in typeMappings)
{
if (typeName.Contains(mapping.OldTypeName))
{
alternateAssembly = mapping.NewAssemblyName;
alternateTypeName = mapping.NewTypeName;
needToMap = true;
break;
}
}
if (needToMap)
{
bool isList = false;
if (typeName.Contains("List`1"))
isList = true;
// other generics need to go here
if (isList)
return Type.GetType(String.Format("System.Collections.Generic.List`1[[{0}, {1}]]", alternateTypeName, alternateAssembly));
else
return Type.GetType(String.Format("{0}, {1}", alternateTypeName, alternateAssembly));
}
else
return null; // this seems to do the trick for binary serialization, but i'm not sure if it is supposed to work
}
}
Run Code Online (Sandbox Code Playgroud)
这可以工作(而不是你的覆盖).
public override Type BindToType(string assemblyName, string typeName)
{
var m = Regex.Match(typeName, @"^(?<gen>[^\[]+)\[\[(?<type>[^\]]*)\](,\[(?<type>[^\]]*)\])*\]$");
if (m.Success)
{ // generic type
var gen = GetFlatTypeMapping(m.Groups["gen"].Value);
var genArgs = m.Groups["type"]
.Captures
.Cast<Capture>()
.Select(c =>
{
var m2 = Regex.Match(c.Value, @"^(?<tname>.*)(?<aname>(,[^,]+){4})$");
return BindToType(m2.Groups["aname"].Value.Substring(1).Trim(), m2.Groups["tname"].Value.Trim());
})
.ToArray();
return gen.MakeGenericType(genArgs);
}
return GetFlatTypeMapping(assemblyName,typeName);
}
Run Code Online (Sandbox Code Playgroud)
然后你只需要实现你的方式GetFlatTypeMapping函数(不要担心泛型参数).
您需要做的是在被询问时返回typeof(List<>)和typeof(Dictionary<,>)(或您想要使用的任何其他通用).
嗯:我说了typeof(List<>)!不typeof(List<something>)......那很重要.
免责声明: 由于正则表达式"(?[^]]*)",这个剪辑不支持嵌套的泛型类型,如List<List<string>>...你将不得不调整一下来支持它!
dod*_*ron -2
您必须使用 BinaryFormatter 进行反/序列化是硬性要求吗?
如果使用 BinaryFormatter 进行序列化不是硬性要求,请考虑其他序列化方法,例如 JSON.Net 或 ProtoBuf.Net。其中任何一个都会创建与平台和版本无关的数据序列化。
或者,您可以自己执行二进制序列化(这比 BinaryFormatter 更快、更小,但通常代码更密集,因为您必须确保编写的序列化器和反序列化器基本上彼此相同。
如果必须使用 BinaryFormatter,请务必使用 FormatterAssemblyStyle.Simple 构造它,以解决版本控制问题。这告诉它不要对汇编版本进行迂腐的检查。
| 归档时间: |
|
| 查看次数: |
5268 次 |
| 最近记录: |