Protobuf-Net 无法在没有无参数构造函数的情况下反序列化记录

Posted

技术标签:

【中文标题】Protobuf-Net 无法在没有无参数构造函数的情况下反序列化记录【英文标题】:Protobuf-Net Cannot Deserialize Record Without Parameterless Constructor 【发布时间】:2021-09-04 13:58:40 【问题描述】:

考虑以下代码示例;我希望能够使用 protobuf-net 序列化(工作正常)和反序列化(不起作用)Account 记录:

public abstract record State

    public abstract ISet<Identity> Identities  get; 

    public SerializedState Serialize()
    
        using MemoryStream stream = new();
        Serializer.Serialize(stream, this);
        return new SerializedState(stream.ToArray(), GetType());
    


public sealed record Account(Identity Owner, string Identifier, decimal Balance) : State

    public override ISet<Identity> Identities => new HashSet<Identity> Owner;

ProtoBuf 合约配置有效:

RuntimeTypeModel
    .Default
    .Add<Account>()
    .Add(nameof(Account.Owner))
    .Add(nameof(Account.Identifier))
    .Add(nameof(Account.Balance));

但我得到以下异常:

ProtoBuf.ProtoException:没有为 Example.Account 找到无参数构造函数

有没有办法配置反序列化(不使用属性)以允许没有无参数构造函数的记录?

【问题讨论】:

我认为这个之前的答案应该会有所帮助:***.com/a/65123415/214073 @KijanaWoodard 我直接与 Marc Gravell 进行了交谈~in~。他说继承也是一样,稍微复杂一点,但目前还没有官方回答。 我不认为您可以提供minimal reproducible example 可以吗?我怀疑***.com/a/65123415/214073 的解决方法可以工作,但是您的代码无法编译,所以我不能肯定地说。见dotnetfiddle.net/hSGMnE。 似乎设置MetaType.UseConstructor = false 确实有效,请参阅dotnetfiddle.net/N9siZk。这回答了你的问题了吗?如果没有,你能分享一个minimal reproducible example 显示什么不起作用吗? 【参考方案1】:

记录的属性默认为init-only,因此实际上可以通过protobuf-net 反射设置。因此,您的Account 记录可以由protobuf-net 反序列化,方法是绕过this answer 中解释的构造函数,由Marc Gravell 到Does protobuf-net support C# 9 positional record types?

由于您是在运行时为Account 初始化合约,因此请修改您的初始化代码以设置MetaType.UseConstructor = false,如下所示:

var accountMeta = RuntimeTypeModel
    .Default
    .Add<Account>()
    .Add(nameof(Account.Owner))
    .Add(nameof(Account.Identifier))
    .Add(nameof(Account.Balance));          
accountMeta.UseConstructor = false;

现在你可以这样做了:

var account = new Account(identity, "Foo", 1.1m);       
var state = account.Serialize();
var account2 = (Account)Serializer.NonGeneric.Deserialize(state.Type, new MemoryStream(state.Data));

我假设SerializedState 看起来像这样:

public class SerializedState

    public SerializedState(byte [] data, Type type) => (Data, Type) = (data, type);
    
    public byte [] Data  get; set; 
    public System.Type Type  get; set; 

演示小提琴here.

【讨论】:

感谢您的帮助,真的很有帮助!我不认为你可以看看我的下一个问题,你可以吗;-) ***.com/questions/69383475/…

以上是关于Protobuf-Net 无法在没有无参数构造函数的情况下反序列化记录的主要内容,如果未能解决你的问题,请参考以下文章

使用非标准构造函数序列化和反序列化对象 - protobuf-net

是否可以在 WCF 中没有无参数构造函数的情况下序列化对象?

用户没有定义无参数构造函数[重复]

在使用静态构造函数的时候应该注意几点

没有为此对象定义无参数构造函数。在剑道网格中

如何检查类型是不是提供无参数构造函数?