protobuf-net 在 .NET Core 中创建的类型在 .NET Framework 中反序列化时出现错误。

huangapple go评论67阅读模式
英文:

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 = @&quot;C:\temp\testClassNetFramework.pbf&quot;, writeToFile2 = @&quot;C:\temp\testClassNET.pbf&quot;;
        framework = Assembly.GetEntryAssembly()?.GetCustomAttribute&lt;TargetFrameworkAttribute&gt;()?.FrameworkName;
        Console.WriteLine(&quot;Current framework is &quot; + framework);
        string writeToFile;
        if (framework.Contains(&quot;.NETFramework&quot;, StringComparison.OrdinalIgnoreCase)) writeToFile = writeToFile1;
       else if (framework.Contains(&quot;.NETCoreApp&quot;, StringComparison.OrdinalIgnoreCase)) writeToFile = writeToFile2;
        else throw new Exception(&quot;haven&#39;t allowed for framework &quot; + framework);
        var tc = make();

        write(tc, writeToFile);
        Console.WriteLine($&quot;\n\nwritten to: {writeToFile}\n{tc.ToString()}&quot;);

        if (File.Exists(writeToFile1))
        {
            var tc1 = Load(writeToFile1);
            Console.WriteLine($&quot;\n\nread from: {writeToFile1}\n{tc1.ToString()}&quot;);
        }

        if (File.Exists(writeToFile2))
        {
            var tc2 = Load(writeToFile2);
            Console.WriteLine($&quot;\n\nread from: {writeToFile2}\n{tc2.ToString()}&quot;);
        }
    }

    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&lt;testClass&gt;(ms);

        return tc;
    }

    void write(testClass tc, string fullFileName)
    {
        MemoryStream ms = new MemoryStream();
        Serializer.Serialize&lt;testClass&gt;(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&lt;string&gt;();
    }
    [ProtoMember(1)]
    public string frameworkWhenSaved { get; set; }
    [ProtoMember(2)]
    public string aType { get; set; }
    [ProtoMember(3)]
    public List&lt;string&gt; types { get; set; } 
}

protobuf-net可以正确地反序列化到这个类:

[ProtoContract]
public class testClass
{
    public testClass()
    {
        types = new List&lt;Type&gt;();
    }
    [ProtoMember(1)]
    public string frameworkWhenSaved { get; set; }
    [ProtoMember(2)]
    public Type aType { get; set; }
    [ProtoMember(3)]
    public List&lt;Type&gt; 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&lt;string&gt;();
    }
    [ProtoMember(1)]
    public string frameworkWhenSaved { get; set; }
    [ProtoMember(2)]
    public string aType { get; set; }
    [ProtoMember(3)]
    public List&lt;string&gt; types { get; set; } 
}

and protobuf-net can correctly deserialize to this class:

[ProtoContract]
public class testClass
{
    public testClass()
    {
        types = new List&lt;Type&gt;();
    }
    [ProtoMember(1)]
    public string frameworkWhenSaved { get; set; }
    [ProtoMember(2)]
    public Type aType { get; set; }
    [ProtoMember(3)]
    public List&lt;Type&gt; types { get; set; }
}

huangapple
  • 本文由 发表于 2023年4月4日 10:17:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/75925031.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定