英文:
protobuf-net deserializing Type created in .NET Core incorrectly in .NET Framework
问题
如果我在运行.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("当前框架是 " + framework);
string writeToFile;
if (framework.Contains(".NETFramework", StringComparison.OrdinalIgnoreCase)) writeToFile = writeToFile1;
else if (framework.Contains(".NETCoreApp", StringComparison.OrdinalIgnoreCase)) writeToFile = writeToFile2;
else throw new Exception("尚未允许的框架 " + framework);
var tc = make();
write(tc, writeToFile);
Console.WriteLine($"\n\n写入到:{writeToFile}\n{tc.ToString()}");
if (File.Exists(writeToFile1))
{
var tc1 = Load(writeToFile1);
Console.WriteLine($"\n\n从中读取:{writeToFile1}\n{tc1.ToString()}");
}
if (File.Exists(writeToFile2))
{
var tc2 = Load(writeToFile2);
Console.WriteLine($"\n\n从中读取:{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中运行它时,我得到了预期的输出:
当前框架是 .NETCoreApp,Version=v7.0
写入到:C:\temp\testClassNET.pbf testClass created by .NETCoreApp,Version=v7.0 aType=System.Int64 types=System.Int32,System.Char,
从中读取:C:\temp\testClassNetFramework.pbf testClass created by .NETFramework,Version=v4.7.2 aType=System.Int64 types=System.Int32,System.Char,
从中读取:C:\temp\testClassNET.pbf testClass created by .NETCoreApp,Version=v7.0 aType=System.Int64 types=System.Int32,System.Char,
但是,当我在完整的.NET Framework上运行它时,Types
会被反序列化为null - 仅限于使用.NET Core保存的文件。
当前框架是 .NETFramework,Version=v4.7.2
写入到:C:\temp\testClassNetFramework.pbf testClass created by .NETFramework,Version=v4.7.2 aType=System.Int64 types=System.Int32,System.Char,
从中读取:C:\temp\testClassNetFramework.pbf testClass created by .NETFramework,Version=v4.7.2 aType=System.Int64
types=System.Int32,System.Char,
从中读取:C:\temp\testClassNET.pbf testClass created by .NETCoreApp,Version=v7.0 aType= types=null,null,
(您需要首先在每个框架中运行它一次以生成文件)。为什么Types
不能被正确反序列化?
英文:
If I serialize my class in an app running .NET Core, and then load it in an app running on the full .NET Framework, any variables of type Type
are deserialized as nulls.
Here's my demo code:
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();
}
}
}
When I run it in .NET Core, I get the expected output:
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,
But when I run it on the full .NET Framework, the Types
are deserialized as nulls - only from the file saved with .NET Core.
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,
(You'll need to run it once in each framework to generate the files first).
Why aren't the Types
being deserialized correctly?
答案1
得分: 1
Type
类实际上是一个基类,设计用于继承,你不会真正创建它的实例,因此没有理由对它进行序列化。(我相信有序列化抽象类的理由,但Type
更像是一个静态定义)。请参考这个SO答案,此处 和 此处。
不确定你的testClass
是如何定义的,但如果它看起来像这样,那么可以将其序列化为一个string
:
testClass make()
{
var tc = new testClass();
tc.frameworkWhenSaved = framework;
tc.aType = typeof(long).FullName;
tc.types.Add(typeof(int).FullName);
tc.types.Add(typeof(char).FullName);
return tc;
}
[ProtoContract]
public class testClass
{
public testClass()
{
types = new List<string>();
}
[ProtoMember(1)]
public string frameworkWhenSaved { get; set; }
[ProtoMember(2)]
public string aType { get; set; }
[ProtoMember(3)]
public List<string> types { get; set; }
}
而protobuf-net
可以正确地反序列化到这个类:
[ProtoContract]
public class testClass
{
public testClass()
{
types = new List<Type>();
}
[ProtoMember(1)]
public string frameworkWhenSaved { get; set; }
[ProtoMember(2)]
public Type aType { get; set; }
[ProtoMember(3)]
public List<Type> types { get; set; }
}
英文:
The Type
class is really a base class that is designed to be inherited, and you don't really create instances of it, so there is no reason to serialize it. (I'm sure there are reasons to serialize an abstract class, but Type
is more of a static definition). See this SO answer, here and here.
Not sure how your testClass
is defined, but if it looks something like this, then just serialize to a string
instead:
testClass make()
{
var tc = new testClass();
tc.frameworkWhenSaved = framework;
tc.aType = typeof(long).FullName;
tc.types.Add(typeof(int).FullName);
tc.types.Add(typeof(char).FullName);
return tc;
}
[ProtoContract]
public class testClass
{
public testClass()
{
types = new List<string>();
}
[ProtoMember(1)]
public string frameworkWhenSaved { get; set; }
[ProtoMember(2)]
public string aType { get; set; }
[ProtoMember(3)]
public List<string> types { get; set; }
}
and protobuf-net
can correctly deserialize to this class:
[ProtoContract]
public class testClass
{
public testClass()
{
types = new List<Type>();
}
[ProtoMember(1)]
public string frameworkWhenSaved { get; set; }
[ProtoMember(2)]
public Type aType { get; set; }
[ProtoMember(3)]
public List<Type> types { get; set; }
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论