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