gpt4 book ai didi

c# - 如何正确使用派生类作为 Microsoft Bond 对象的字段

转载 作者:行者123 更新时间:2023-11-30 21:43:02 24 4
gpt4 key购买 nike

所以没有混淆,当我讨论我的问题时,我是以使用由 Bond 模式产生的编译类的人的身份这样做的(也就是说我使用“类”而不是“结构”等) .我觉得这样想在认知上更有意义。

我正在使用 Microsoft Bond,我有一个主类,它有几个属性,其中一个是派生类的实例。

创建主类的实例时,我可以毫无问题地将属性设置为派生类的实例;然而,当我从二进制反序列化回主类时,该属性现在被视为它的基类。

我曾尝试将其转换为派生类,但会抛出运行时异常。

Bond 文档/手册中使用派生类的示例让您在反序列化时指定派生类,但我不只是反序列化派生类,而是反序列化主类。

这是我如何设置绑定(bind)模式的示例

struct BaseExample
{
0: int property1;
}

struct DerivedExample : BaseExample
{
0: int property2;
}

struct MainExample
{
0: BaseExample mainProperty;
}

在使用中,我将 mainProperty 设置为 DerivedExample 类的一个实例。我期望的是,在反序列化之后,mainProperty 仍然是 DerivedExample 类型(包含 property2),但我看到的是 mainProperty 是 BaseExample 类型(并且不包含 property2)

我是被迫使用泛型来做这件事还是我遗漏了什么?

编辑:添加示例

我使用从 Bond 模式生成的类的代码是这样的。

我们有一个调用服务来创建这种类型的消息,并使用 Bond 将其序列化为字节数组,然后再通过流发送。

var message = new MainExample();

var derivedExample = new DerivedExample()
{
property1 = 1,
property2 = 2,
};
message.mainProperty = derivedExample;

// This block is all from the Bond examples
var output = new OutputBuffer();
var writer = new CompactBinaryWriter<OutputBuffer>(output);
Serialize.To(writer, message);

SendMessage(output.Data.Array);

现在我们有一个接收服务,它将把这个消息从流中取出并使用 Bond 将它反序列化回一个对象。

void HandleMessage(byte[] messageBA)
{
// This block is all from the Bond examples
var input = new InputBuffer(messageBA);
var reader = new CompactBinaryReader<InputBuffer>(input);
MainExample message = Deserialize<BondEvent>.From(reader);

// mainProperty is now of type BaseExample and not DerivedExample
message.mainProperty.property1; // is accessable
message.mainProperty.property2; // will not compile

DerivedExample castedProperty = message.mainProperty as DerivedExample; // fails at runtime
}

完全披露:我实际上使用的是 F#,但我认为在 C# 中执行这些操作会更好

最佳答案

您在反序列化时观察到的切片行为在写入的模式中是预期的。 MainExample.mainProperty字段类型为 BaseExample ,所以当它被序列化时,只有 BaseExample字段被写入。使用哪种运行时类型并不重要。此外,反序列化时,只有 BaseExample字段将被实现。

在处理继承和多态性时,Bond 不在序列化有效负载中包含任何类型信息:它将如何建模的决定留给模式设计者。这源于 Bond 只为使用的东西付费的理念。

根据您建模的数据,我看到了两种设计架构的方法:

  1. 泛型
  2. bonded

泛型

如问题中所述,MainExample结构可以被通用化:

struct MainExample<T>
{
0: T mainProperty;
}

这基本上可以让您轻松创建一堆具有相似形状的不同结构。但是这些结构不会有"is"关系。类似 HandleMessage 的方法可能还必须是通用的,从而导致通用级联。

保税

要在另一个类型多态的结构中包含一个字段,请将该字段设置为 bonded field .绑定(bind)字段在序列化时不切片。此外,它们不会立即反序列化,因此接收方有机会选择合适的类型进行反序列化。

在 .bond 文件中,我们有这个:

struct MainExample
{
0: bonded<BaseExample> mainProperty;
}

要序列化,请执行以下操作:

var message = new MainExample();

var derivedExample = new DerivedExample()
{
property1 = 1,
property2 = 2,
};
message.mainProperty = new Bonded<DerivedExample>(derivedExample);
// NB: new Bonded<BaseExample>(derivedExample) WILL slice

反序列化:

void HandleMessage(byte[] messageBA)
{
// This block is all from the Bond examples
var input = new InputBuffer(messageBA);
var reader = new CompactBinaryReader<InputBuffer>(input);
MainExample message = Deserialize<BondEvent>.From(reader);

DerivedExample de = message.mainProperty.Deserialize<DerivedExample>();
}

使用 bonded 时多态性的字段,我们需要有一些方法来知道要反序列化到哪个派生类型。有时这是从有效载荷外部的上下文中获知的(例如,可能处理的每个消息只有一种类型)。其他时候,我们需要将此信息嵌入有效负载的公共(public)部分。一种常见的方法是使用枚举:

enum PropertyKind
{
Base;
Derived;
}

struct MainExample
{
0: bonded<BaseExample> mainProperty;
1: PropertyKind mainPropertyKind = Base;
}

在 C# polymorphic_container 中有一个执行这种分派(dispatch)的完整示例。 Bond 存储库中的示例。

OutputBuffer.Data.Array

我注意到在发送消息的代码中,有以下一行,其中包含一个错误:

SendMessage(output.Data.Array);

OutputBuffer.Data属性是 ArraySegment<byte> ,用于表示其他数组的一部分。此切片可能比整个数组(Count 属性)短,并且它可能从 0 以外的偏移量开始(Offset 属性)。大多数 I/O 库都有像 SendMessage(byte[] buf, int offset, int count) 这样的重载可以在这种情况下使用。

支持 OutputBuffer 的默认数组是 65K,所以几乎可以肯定发送了一堆额外的数据。

关于c# - 如何正确使用派生类作为 Microsoft Bond 对象的字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42075814/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com