简体   繁体   English

protobuf-net 是否支持 C# 9 位置记录类型?

[英]Does protobuf-net support C# 9 positional record types?

I'm trying to use protobuf-net with C# positional record types, and I've encountered this exception:我正在尝试将 protobuf-net 与 C# 位置记录类型一起使用,我遇到了这个异常:

10:18:48.048 [EROR] #010 (Microsoft.AspNetCore.Server.Kestrel) Connection id ""0HM4NDHMUB3C6"", Request id ""0HM4NDHMUB3C6:00000003"": An unhandled exception was thrown by the application.
Grpc.Core.RpcException: Status(StatusCode="Internal", Detail="Error starting gRPC call. ProtoException: No parameterless constructor found for Bidirectional.Demo.Common.Contracts.Server.GetServerProcessI
nfo.GetServerProcessInfoResponse", DebugException="ProtoBuf.ProtoException: No parameterless constructor found for Bidirectional.Demo.Common.Contracts.Server.GetServerProcessInfo.GetServerProcessInfoResp
onse
   at ProtoBuf.Internal.ThrowHelper.ThrowProtoException(String message, Exception inner) in /_/src/protobuf-net.Core/Internal/ThrowHelper.cs:line 70
   at ProtoBuf.Meta.TypeModel.ThrowCannotCreateInstance(Type type, Exception inner) in /_/src/protobuf-net.Core/Meta/TypeModel.cs:line 1666
   at proto_12(State& , GetServerProcessInfoResponse )
   at ProtoBuf.Internal.Serializers.SimpleCompiledSerializer`1.ProtoBuf.Serializers.ISerializer<T>.Read(State& state, T value)
   at ProtoBuf.ProtoReader.State.ReadAsRoot[T](T value, ISerializer`1 serializer)
   at ProtoBuf.ProtoReader.State.DeserializeRoot[T](T value, ISerializer`1 serializer)
   at ProtoBuf.Meta.TypeModel.Deserialize[T](ReadOnlySequence`1 source, T value, Object userState)
   at ProtoBuf.Grpc.Configuration.ProtoBufMarshallerFactory.ContextualDeserialize[T](DeserializationContext context)

This is what GetServerProcessInfoResponse looks like:这就是 GetServerProcessInfoResponse 的样子:

[ProtoContract]
public record GetServerProcessInfoResponse(
    [property: ProtoMember(1)] TimeSpan TotalProcessorTime,
    [property: ProtoMember(2)] TimeSpan UserProcessorTime,
    [property: ProtoMember(3)] TimeSpan PrivilegedProcessorTime,
    [property: ProtoMember(4)] string CurrentMemoryUsage,
    [property: ProtoMember(5)] string PeakMemoryUsage,
    [property: ProtoMember(6)] int ActiveThreads
);

The code works fine if I change GetServerProcessInfoResponse into a regular C# class with gettable and settable properties.如果我将 GetServerProcessInfoResponse 更改为具有可获取和可设置属性的常规 C# class ,则代码可以正常工作。 I was hoping however that records could work too, because they avoid a whole lot of nullability warnings.但是,我希望记录也可以工作,因为它们避免了很多可空性警告。 System.Text.Json has support for deserializing records for example, which has to work against the same limitations. System.Text.Json 支持例如反序列化记录,这必须克服相同的限制。

I couldn't find anything in the docs, issues or here on StackOverflow, so maybe I'm bad at searching, or maybe the answer isn't out there yet.我在文档、问题或 StackOverflow 上找不到任何东西,所以也许我不擅长搜索,或者答案可能还没有。 :-) :-)

The protobuf-net repository also doesn't seem to have any unit tests that try to serialize / deserialize a c# record, it only contains "RecordTypeTests" which seems to be checking if records can be cloned? protobuf-net 存储库似乎也没有任何单元测试尝试序列化/反序列化 c# 记录,它只包含“RecordTypeTests”,它似乎正在检查是否可以克隆记录?

Yes, in two different ways.是的,有两种不同的方式。

With your existing code, the simplest option is to tell protobuf-net to perform voodoo to get past the fact there is no available constructor;使用您现有的代码,最简单的选择是告诉 protobuf-net 执行 voodoo 以克服没有可用构造函数的事实; fortunately, this is simple:幸运的是,这很简单:

[ProtoContract(SkipConstructor = true)]
public record GetServerProcessInfoResponse(
    [property: ProtoMember(1)] TimeSpan TotalProcessorTime,
    [property: ProtoMember(2)] TimeSpan UserProcessorTime,
    [property: ProtoMember(3)] TimeSpan PrivilegedProcessorTime,
    [property: ProtoMember(4)] string CurrentMemoryUsage,
    [property: ProtoMember(5)] string PeakMemoryUsage,
    [property: ProtoMember(6)] int ActiveThreads
);

However, With recent builds of the v3 code, it will also infer what you are trying to do specifically in the case of purely positional records , ie the following should work too, and mean more or less the same thing (as a minute detail: it will actually use the constructor in this case, instead of creating an instance via voodoo and then stomping the values):但是,随着 v3 代码的最新版本,它还将推断在纯位置记录的情况下具体尝试做什么,即以下内容也应该工作,并且或多或少意味着相同的事情(作为一个微小的细节:在这种情况下,它实际上会使用构造函数,而不是通过 voodoo 创建一个实例然后踩踏值):

public record GetServerProcessInfoResponse(
    TimeSpan TotalProcessorTime,
    TimeSpan UserProcessorTime,
    TimeSpan PrivilegedProcessorTime,
    string CurrentMemoryUsage,
    string PeakMemoryUsage,
    int ActiveThreads
);

Records will work , and as comments and Marc's answer here shows, the issue is with the constructor, not that it is a record type.记录将起作用,正如评论和 Marc 在此处的回答所示,问题出在构造函数上,而不是记录类型。

Record types are just classes, with compiler-generated code and attributes.记录类型只是类,具有编译器生成的代码和属性。

To show a different way to get to where you want, you could just add the parameterless constructor.要显示到达所需位置的不同方式,您可以添加无参数构造函数。 Yes, it's a little bit more work than just the naive record declaration, but if you're stuck with a version of ProtoBuf that doesn't support parameterized constructors, and you don't want to bypass the constructors like Marc showed, here's a different option:是的,这比单纯的记录声明要多一点工作,但是如果你被一个不支持参数化构造函数的 ProtoBuf 版本困住,并且你不想像 Marc 显示的那样绕过构造函数,这里有一个不同的选择:

[ProtoContract]
public record GetServerProcessInfoResponse(
    [property: ProtoMember(1)] TimeSpan TotalProcessorTime,
    [property: ProtoMember(2)] TimeSpan UserProcessorTime,
    [property: ProtoMember(3)] TimeSpan PrivilegedProcessorTime,
    [property: ProtoMember(4)] string CurrentMemoryUsage,
    [property: ProtoMember(5)] string PeakMemoryUsage,
    [property: ProtoMember(6)] int ActiveThreads
)
{
    public GetServerProcessInfoResponse() : this(default, default, default, default, default, default) { }
}

This lets you use the basic positional record declaration, but allows you to add the parameterless constructor that ProtoBuf <3 wants.这允许您使用基本的位置记录声明,但允许您添加 ProtoBuf <3 想要的无参数构造函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM