gpt4 book ai didi

c# - 如何为 Binary Formatter 创建一个 SerializationBinder 来处理类型从一个程序集和命名空间到另一个的移动

转载 作者:太空狗 更新时间:2023-10-29 17:56:16 27 4
gpt4 key购买 nike

上下文如下

  1. 我想通过将代码移动到不同的项目来重构代码
  2. 部分代码由可序列化的 DTO 组成,用于跨多个端点发送和接收数据
  3. 如果我四处移动代码,序列化就会中断(因此它不是向后兼容我的应用程序的旧版本)

这个问题的解决方案是 SerializationBinder,它允许我在某种意义上从一种类型“重定向”到另一种类型。

因此我想创建一个 SerializationBinder 来满足这个需求。但是,它必须满足以下要求才能做到这一点

  1. SerializationBinder 的输入应该是旧类型的列表到新的类型映射。映射应包括旧程序集名称(无版本,无公钥 token )和旧的全名类型(命名空间和名称)以及新程序集名称和新类型全名
  2. 对于输入中的类型,应忽略程序集的版本号
  3. 如果我的类型碰巧是泛型,它应该处理泛型(列表、字典等)无需在输入中包含泛型
  4. 对于任何不在输入中的东西(即没有的类型移动或 .NET 类型,例如数据集)它应该默认为使用二进制序列化器的开箱即用算法

这是可能的还是我在做梦?有什么东西已经做到了吗?我认为这是一个常见问题。

到目前为止,我看不到做 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
}
}

最佳答案

这可以工作(而不是你的覆盖)。

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

然后您只需按照自己的方式实现函数 GetFlatTypeMapping(无需担心通用参数)。

您需要做的是返回 typeof(List<>)typeof(Dictionary<,>) (或任何其他你想使用的通用)在被问到时。

注意:我说 typeof(List<>) !不是typeof(List<something>) ...这很重要。

免责声明:由于正则表达式“(?[^]]*)”,此片段不支持嵌套的泛型类型,如 List<List<string>> ...您将不得不稍微调整一下以支持它!

关于c# - 如何为 Binary Formatter 创建一个 SerializationBinder 来处理类型从一个程序集和命名空间到另一个的移动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19666511/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com