Data Contract Serializer обязывает суперкласс знать о подклассе - PullRequest
1 голос
/ 25 июня 2011

У меня есть эта проблема, «У десериализатора нет знаний любого типа, которые соответствуют этому контракту» После поиска в Google, я достиг этого поста

Десериализатор не обладает знаниями любого типа, которые соответствуют этому контракту

где ответ говорит, базовый класс должен объявить "KnownTypes" как [DataContract, KnownType (typeof (Subclass)) ...],

Если мне нужно объявить это в моем родительском классе, [DataContract, KnownType (typeof (Subclass))], разве это не нарушает принципы OO Design, которые родительский класс не должен знать о подклассе?

Как правильно это сделать?

Ответы [ 2 ]

3 голосов
/ 25 июня 2011

Сериализатор разработан таким образом, что, если он сериализует объект, он должен иметь возможность прочитать его обратно.Если вы попытаетесь сериализовать объект с объявленным типом «Base», но фактическим типом «Derived» (см. Пример ниже), если вы хотите иметь возможность считывать из сериализованного объекта экземпляр «Derived»,вам нужно как-то аннотировать XML-код, экземпляр которого не относится к тому типу, который был объявлен.

[DataContract]
public class MyType
{
    [DataMember]
    public object obj = new Derived();
}

Сериализованная версия этого типа будет выглядеть примерно так, как показано ниже:

<MyType>
  <obj actualType="Derived">
    <!-- fields of the derived type -->
  </obj>
</MyType>

Когда тип десериализуется, сериализатор будет смотреть на атрибут «actualType» (не фактическое имя), и ему нужно будет найти этот тип, инициализировать его и установить его свойства.Это потенциальная проблема безопасности, позволяющая сериализатору (поскольку в Silverlight life это доверенная сборка и имеет больше «прав», чем у обычного пользовательского кода) для создания произвольного типа, так что это одна из причин ограничения типов, которые можно десериализовать.И исходя из конструкции сериализатора (если мы можем сериализовать его, мы должны быть в состоянии десериализовать его), сериализация также завершается неудачей по этой причине.

Другая проблема заключается в том, что сериализованные данные частоиспользуется для связи между различными службами, на разных компьютерах и, возможно, на разных языках.Возможно (и часто это так), что у вас есть класс в пространстве имен на клиенте, который имеет контракт данных , аналогичный классу на стороне сервера, но они имеют разные имена и / или находятсяв разных пространствах имен.Поэтому простое добавление имени типа CLR в атрибут «actualType» также не сработает в этом сценарии (атрибут [KnownType] помогает serialzier сопоставить имя / пространство имен контракта данных с фактическим типом CLR).Кроме того, если вы говорите со службой на другом языке / платформе (например, Java), имена типов CLR даже не имеют смысла.

Другое более подробное объяснение дано в посте http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,a3775eb1-b441-43ad-b9f1-e4aaba404235.aspx - здесь говорится о [ServiceKnownType] вместо [KnownType], но принципы те же.

Наконец, по вашему вопросу: нарушает ли этот ОО-принцип?Да, этот принцип нарушен, это цена, которую нужно заплатить за возможность потерять связь между клиентом и сервисами в вашем распределенном (сервис-ориентированном) приложении.

2 голосов
/ 25 июня 2011

Да, это нарушает принципы ОО дизайна. Это связано с тем, что SOA заключается в совместном использовании контрактов (C в ABC сервисов), а не в типах, а OO - в иерархиях типов. Подумайте, что клиент для сервиса может быть даже не на языке OO, но принципы SOA все еще могут применяться. То, как сопоставление выполняется на стороне сервера, является проблемой реализации.

...