2017-02-06 2 views
2

Так что нет никакой путаницы, когда я говорю по моей проблеме, я делаю это как кто-то, кто использует скомпилированные классы, которые являются результатом схем Bond (то есть Я использую «класс» вместо «struct» и т. Д.). Я чувствую, что это делает больше когнитивного смысла думать об этом таким образом.Как правильно использовать производные классы в качестве полей объекта Microsoft Bond

Я использую Microsoft Bond, и у меня есть основной класс, который имеет несколько свойств, один из которых является экземпляром производного класса.

При создании экземпляра основного класса у меня нет проблем с установкой свойства экземпляру производного класса; однако, когда я deserialize из двоичного обратно в основной класс, свойство теперь рассматривается как его базовый класс.

Я попытался использовать его как производный класс, но это исключает исключение во время выполнения.

В примерах использования производных классов в документации/руководстве Bond вы указываете производный класс во время десериализации, но я не десериализую только производный класс, а основной класс.

Вот пример того, как у меня есть схема связи создана

struct BaseExample 
{ 
    0: int property1; 
} 

struct DerivedExample : BaseExample 
{ 
    0: int property2; 
} 

struct MainExample 
{ 
    0: BaseExample mainProperty; 
} 

В использовании я устанавливаю mainProperty к экземпляру класса DerivedExample. То, что я бы ожидать, что после десериализации, mainProperty еще из DerivedExample типа (содержащий свойство2), но то, что я вижу вместо этого mainProperty имеет BaseExample типа (и не содержит свойство2)

я вынужден использовать дженерики, чтобы сделать это, или есть что-то, чего я не хватает?

EDIT: Добавление примеров

Мой код, который использует классы, полученные от схем Бонде, как это.

У нас есть служба вызова, которая создает сообщение этого типа и использует 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#

+0

Я не совсем уверен, что вы настраиваете на то, что и что вы видите, это неправильно.Можете ли вы отредактировать вопрос, чтобы показать, как вы создаете, устанавливаете, сериализуете, десериализируете и проверяете структуры? – chwarr

+0

Я пересказывал некоторые вещи и добавлял примеры, мне жаль, что я не знаю, как сделать это проще объяснить. Дьявол определенно в деталях касается моего вопроса. Но если есть что-то конкретное, я могу прояснить, пожалуйста, дайте мне знать, и я попробую. Я убежден, что если я сериализую конкретную реализацию производного типа, десериализатор должен иметь возможность создавать экземпляр того же типа, который был сериализован. Я этого не вижу, так что либо я делаю это неправильно, либо это невозможно, и это прекрасно, мне просто нужно знать наверняка, прежде чем переключиться на использование дженериков (что действительно работает). – GoodGuyJim

+0

Получил то, что мне нужно (редактирование структуры 'MainExample', которая изменила тип' mainProperty'), чтобы ответить на вопрос. – chwarr

ответ

2

Поведение нарезка, что вы наблюдаете при десериализации, как ожидается, со схемами, как написано. Поле MainExample.mainProperty имеет тип BaseExample, поэтому, когда оно сериализовано, записываются только поля BaseExample. Не имеет значения, какой тип времени выполнения используется. Кроме того, когда он десериализуется, будут реализованы только поля BaseExample.

Когда речь идет о наследовании и полиморфизме, Bond не включает в себя информацию о типе в сериализованной полезной нагрузке: она оставляет решение о том, как моделировать это до дизайнера схемы. Это связано с философией Бонда только за то, что вы используете.

В зависимости от данных, которые вы моделируете, я вижу два пути для проектирования вашей схеме:

  1. дженерики
  2. bonded

Generics

Как упомянуто в вопросе, то MainExample Структура может быть общей:

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

Это, по сути, позволяет легко создавать кучу разных структур с похожими формами. Но эти структуры не будут иметь отношения «есть». Вероятно, методы, подобные HandleMessage, также будут носить общий характер, вызывая общий каскад.

Кабальный

Чтобы включить поле в другой структуры, которая является полиморфным типом, сделать поле а bonded field. Склеенные поля не секционируются при сериализации. Кроме того, они не сразу десериализуются, поэтому принимающая сторона имеет возможность выбрать подходящий тип для десериализации.

В .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 полей для полиморфизма, нам нужно будет иметь некоторый способ узнать, какой наиболее производный тип десериализуется. Иногда это известно из контекста, внешнего по отношению к полезной нагрузке (например, возможно, каждый из обработанных сообщений имеет только один тип). В других случаях нам необходимо встроить эту информацию в общую часть полезной нагрузки. Обычный способ сделать это с помощью перечисления:

enum PropertyKind 
{ 
    Base; 
    Derived; 
} 

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

Там в полностью работал пример выполнения такого рода отправки в примере C# polymorphic_container в хранилище Бонде.

OutputBuffer.Data.Array

Я заметил, что в коде, чтобы отправить сообщение, есть следующая строка, которая содержит ошибку:

SendMessage(output.Data.Array); 

Свойство OutputBuffer.Data является ArraySegment<byte>, который используется для представления срез другого массива. Этот срез может быть короче, чем весь массив (свойство Count), и он может начинаться со смещения, отличного от 0 (свойство Offset). Большинство библиотек ввода-вывода имеют перегрузку, такую ​​как SendMessage(byte[] buf, int offset, int count), которая может использоваться в таких случаях.

По умолчанию массив, поддерживающий OutputBuffer, составляет 65 тыс., Поэтому почти наверняка будет отправлено множество дополнительных данных.

+0

Большое вам спасибо за это, мы очень ценим это! – GoodGuyJim

Смежные вопросы