protobuf-net跨框架反序列化异常:.NET Core序列化Type在.NET Framework中为null
.NET Core序列化含Type类型的类,在.NET Framework反序列化时Type变量为null
在.NET Core应用中序列化自定义类后,在完整.NET Framework应用中加载时,所有Type类型的变量反序列化后均为null。
演示代码
public class protobufTest { string framework; public protobufTest() { string writeToFile1 = @"C:\temp\testClassNetFramework.pbf", writeToFile2 = @"C:\temp\testClassNET.pbf"; framework = Assembly.GetEntryAssembly()?.GetCustomAttribute<TargetFrameworkAttribute>()?.FrameworkName; Console.WriteLine("Current framework is " + framework); string writeToFile; if (framework.Contains(".NETFramework", StringComparison.OrdinalIgnoreCase)) writeToFile = writeToFile1; else if (framework.Contains(".NETCoreApp", StringComparison.OrdinalIgnoreCase)) writeToFile = writeToFile2; else throw new Exception("haven't allowed for framework " + framework); var tc = make(); write(tc, writeToFile); Console.WriteLine($"\n\nwritten to: {writeToFile}\n{tc.ToString()}"); if (File.Exists(writeToFile1)) { var tc1 = Load(writeToFile1); Console.WriteLine($"\n\nread from: {writeToFile1}\n{tc1.ToString()}"); } if (File.Exists(writeToFile2)) { var tc2 = Load(writeToFile2); Console.WriteLine($"\n\nread from: {writeToFile2}\n{tc2.ToString()}"); } } testClass make() { var tc = new testClass(); tc.frameworkWhenSaved = framework; tc.aType = typeof(long); tc.types.Add(typeof(int)); tc.types.Add(typeof(char)); return tc; } testClass Load(string fullFileName) { MemoryStream ms; using (FileStream file = new FileStream(fullFileName, FileMode.Open, FileAccess.Read)) { byte[] bytes = new byte[file.Length]; file.Read(bytes, 0, (int)file.Length); ms = new MemoryStream(bytes); } ms.Position = 0; testClass tc = Serializer.Deserialize<testClass>(ms); return tc; } void write(testClass tc, string fullFileName) { MemoryStream ms = new MemoryStream(); Serializer.Serialize<testClass>(ms, tc); ms.Position = 0; using (FileStream file = new FileStream(fullFileName, FileMode.Create, System.IO.FileAccess.Write)) { byte[] bytes = new byte[ms.Length]; ms.Read(bytes, 0, (int)ms.Length); file.Write(bytes, 0, bytes.Length); ms.Close(); } } }
运行结果
.NET Core运行时输出(符合预期)
Current framework is .NETCoreApp,Version=v7.0 written to: C:\temp\testClassNET.pbf testClass created by .NETCoreApp,Version=v7.0 aType=System.Int64 types=System.Int32,System.Char, read from: C:\temp\testClassNetFramework.pbf testClass created by .NETFramework,Version=v4.7.2 aType=System.Int64 types=System.Int32,System.Char, read from: C:\temp\testClassNET.pbf testClass created by .NETCoreApp,Version=v7.0 aType=System.Int64 types=System.Int32,System.Char,
.NET Framework运行时输出(Type变量为null)
Current framework is .NETFramework,Version=v4.7.2 written to: C:\temp\testClassNetFramework.pbf testClass created by .NETFramework,Version=v4.7.2 aType=System.Int64 types=System.Int32,System.Char, read from: C:\temp\testClassNetFramework.pbf testClass created by .NETFramework,Version=v4.7.2 aType=System.Int64 types=System.Int32,System.Char, read from: C:\temp\testClassNET.pbf testClass created by .NETCoreApp,Version=v7.0 aType= types=null,null,
(需先在两个框架中各运行一次生成文件)
问题原因
这是因为.NET Core(及.NET 5+)和.NET Framework中Type类型的序列化格式、底层程序集命名存在差异:
- Protobuf-NET默认序列化Type时,.NET Core使用的是简化的程序集标识(比如依赖
System.Runtime),而.NET Framework依赖的是mscorlib,两者的类型标识无法直接兼容。 - 跨框架时,Protobuf-NET无法识别对方生成的Type序列化标识,导致类型解析失败,最终返回null。
解决方案
自定义Type的序列化/反序列化逻辑,统一跨框架的类型标识格式:
1. 实现Type的代理类(Surrogate)
public class TypeSurrogate { public string TypeName { get; set; } // 从代理类转换为Type public static implicit operator Type(TypeSurrogate surrogate) { if (string.IsNullOrEmpty(surrogate.TypeName)) return null; // 先尝试直接解析 var type = Type.GetType(surrogate.TypeName, false); if (type != null) return type; // 兼容.NET Core和.NET Framework的程序集差异 var adjustedName = surrogate.TypeName .Replace("System.Runtime, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); return Type.GetType(adjustedName, true); } // 从Type转换为代理类 public static implicit operator TypeSurrogate(Type type) { if (type == null) return null; // 存储类型的完全限定名+程序集信息 return new TypeSurrogate { TypeName = type.AssemblyQualifiedName }; } }
2. 注册代理类到Protobuf-NET
在序列化/反序列化操作前,注册自定义代理:
RuntimeTypeModel.Default.Add(typeof(Type), false).SetSurrogate(typeof(TypeSurrogate));
3. 确保testClass的字段配置正确
为testClass中的Type字段添加[ProtoMember]标记,确保Protobuf-NET能识别并使用代理类处理。
内容的提问来源于stack exchange,提问作者mcmillab
相关产品推荐
相关产品推荐

