частью производного. Именно поэтому классу
System.Object
назначен атрибут
SerializableAttribute
.
ПриМеЧание
В.общем.случае.большинство.типов.лучше.делать.сериализуемыми .Хотя.бы.потому,.
что.это.дает.пользователям.большую.гибкость .Однако.следует.учитывать,.что.при.
сериализации.читаются.все.поля.объекта.вне.зависимости.от.того,.с.каким.модифи-
катором.они.были.объявлены.—.public,.protected,.internal.или.private .Поэтому.если.
тип.содержит.конфиденциальные.или.защищенные.данные.(например,.пароли),.вряд.
ли.стоит.делать.его.сериализуемым
Если.вы.работаете.с.типом,.не.предназначенным.для.сериализации,.а.его.исходный.
код.недоступен,.не.все.потеряно .Чуть.позже.я.расскажу,.как.организовать.сериа-
лизацию.такого.типа
Управление сериализацией
и десериализацией
После назначения типу настраиваемого атрибута
SerializableAttribute
все экзем-
пляры его полей (открытые, закрытые, защищенные и т. п.) становятся сериализу-
674
Глава.24 .Сериализация
емыми
1
.
Впрочем, в типе можно указать некоторые экземпляры как не подлежащие
сериализации. В общем случае это делается по двум причинам:
Поле содержит информацию, становящуюся недействительной после десери-
ализации. Например, сюда относятся объекты, содержащие дескрипторы объ-
ектов ядра Windows (таких, как файлы, процессы, потоки, мьютексы, события,
семафоры и т. п.). Их десериализация в другой процесс или на другую машину
бессмысленна, так как дескрипторы ядра Windows привязаны к конкретному
процессу.
Поля содержат легко обновляемую информацию. В этом случае сделав их не под-
лежащими сериализации, вы уменьшите объем передаваемых данных, а значит,
повысите производительность.
В показанном далее фрагменте кода с помощью настраиваемого атрибута
System.
NonSerializedAttribute
помечаются поля, не подлежащие сериализации (имей-
те в виду, что этот атрибут определен в пространстве имен
System
, а не
System.
Runtime.Serialization
):
[Serializable]
internal class Circle {
private Double m_radius;
[NonSerialized]
private Double m_area;
public Circle(Double radius) {
m_radius = radius;
m_area = Math.PI * m_radius * m_radius;
}
...
}
Объекты класса
Circle
допускают сериализацию, но модуль форматирования
сериализует только значения поля
m_radius
. Значения поля
m_area
не сериализу-
ются, так как этому полю был назначен атрибут
NonSerializedAttribute
. Его на-
значают только полям типа, но действие атрибута распространяется на поля и при
наследовании другим типом. Конечно, в пределах типа он может быть назначен
целому набору полей.
Предположим, в нашем коде объект
Circle
конструируется следующим об-
разом:
Circle c = new Circle(10);
1
В C# внутри типов, помеченных атрибутом [Serializable], не стоит определять автоматиче-
ски реализуемые свойства. Дело в том, что имена полей, генерируемые компилятором, могут
меняться после каждой следующей компиляции, что сделает невозможной десериализацию
экземпляров типа.
675
Управление.сериализацией.и.десериализацией
Полю
m_area
было присвоено значение, равное примерно 314,159. Но при
сериализации объекта в поток ввода-вывода записывается только значение поля
m_radius
, равное 10. Именно этого мы и добивались, но при десериализации потока
обратно в объект
Circle
возникает проблема. Поле
m_radius
получит значение 10,
а вот поле
m_area
станет равным 0, а не 314,159!
Следующий фрагмент кода показывает, как решить эту проблему:
[Serializable]
internal class Circle {
private Double m_radius;
[NonSerialized]
private Double m_area;
public Circle(Double radius) {
m_radius = radius;
m_area = Math.PI * m_radius * m_radius;
}
[OnDeserialized]
private void OnDeserialized(StreamingContext context) {
m_area = Math.PI * m_radius * m_radius;
}
}
Теперь объект
Circle
снабжен методом с настраиваемым атрибутом
System.
Runtime.Serialization.OnDeserializedAttribute
1
. При десериализации экзем-
пляра типа модуль форматирования проверяет наличие в типе метода с данным
атрибутом. При дальнейшем вызове метода все сериализуемые поля получат кор-
ректные значения и к тому же станут доступными для дополнительных операций,
без которых невозможна полная десериализация объекта.
В модифицированной версии объекта
Circle
я заставил метод
OnDeserialized
вычислить площадь круга на основе значения поля
m_radius
, помещая результат
в поле
m_area
. В результате это поле получает нужное нам значение 314,159.
Кроме настраиваемого атрибута
OnDeserializedAttribute
в пространстве
имен
System.Runtime.Serialization
определены также настраиваемые атрибуты
OnSerializing Attribute
,
OnSerializedAttribute
и
OnDeserializingAttribute
,
применив которые к методам нашего типа мы получаем дополнительный контроль
над сериализацией и десериализацией. Пример класса, применяющего к методу
все эти атрибуты:
[Serializable]
public class MyType {
Int32 x, y; [NonSerialized] Int32 sum;
1
Применение настраиваемого атрибута System.Runtime.Serialization.OnDeserialized
является более предпочтительным в случае вызова метода при десериализации объекта,
чем реализация типом метода OnDeserialization интерфейса System.Runtime.Serialization.
IDeserializationCallback.
продолжение
676
Do'stlaringiz bilan baham: |