Главная » C#, Компоненты » Управление кодом сериализации

0

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

Для тестов сделаем специальный компонент с одним-единственным свойством:

public class TestControl : Control {

private string testProperty = "test-value";

public string TestProperty {

get { return testProperty; } set { testProperty = value; }

}

}

Добавим такой компонент на форму и посмотрим код, который генерирует провайдер сериализации (несущественную часть кода я удалил):

this.testControll = new MyControl.TestControl();

//

// testControll

//

this.testControll.Location = new System.Drawing.Point{154, 112); this.testControll.Name = "testControll";

this.testControll.Size = new System.Drawing.Size(75, 23); this.testControll.Tablndex = 0; this.testControll.TestProperty = "test-value"; this.testControll.Text = "testControll";

Код, относящийся к нашему компоненту, состоит из трех блоков: конструктора, комментария и заполнения свойств. Каким образом можно повлиять на этот код?

Для управления кодом сериализации нужно добавить собственный сериали- загор. Сделать это можно С помощью атрибута DesignerSerializer:

[DesignerSerializer(typeof(TestSerializer),

typeof(CodeDomSerializer))] public class TestControl : Control

Первый параметр задает тип сериализатора, а второй — тип базового класса. Соответственно, описание нашего сериализатора должно иметь вид:

public class TestSerializer : CodeDomSerializer ( )

Класс CodeDomseriaiizaer имеет два виртуальных метода, выполняющих базовую функциональность сериализатора. Перекрыв их, мы сможем влиять на процессы сериализации и десериализации:

public class TestSerializer : CodeDomSerializer {

public override object Deserialize(

IDesignerSerializationManager manager, obj ect codeObj ect}

{

return baseClassSerializer.Deserialize{manager, codeObject);

}

public override object Serialize(

IDesignerSerializationManager manager, object value}

{

object codeObject = baseClassSerializer.Serialize{manager, value); return codeObject;

}

}

С помощью интерфейса менеджера сериализации IDesignerSerializationManager можно получить объект самого сериализатора:

CodeDomSerializer baseClassSerializer =

(CodeDomSerializer)manager.GetSerializer(

typeof(TestControl).BaseType, typeof(CodeDomSerializer));

С помощью этого объекта можно управлять содержимым кода, генерируемого сериализатором. Но перед этим я должен рассказать, с помощью каких классов описывается код.

Базовым объектом описания кода (звучит занятно — код классов описывается с помощью классов, но это действительно так) является класс System.codeDom.codeObject. От него наследуются классы, описывающие элементы кода, например:

D CodeComment — комментарий;

D CodeDirective—директива кода;

D codeExpression — выражение;

D codeNamespace — пространство и мен;

D codestatement — абстрактный класс для всех кодовых конструкций. Соответствующие наборы элементов описываются коллекциями: D CodeCommentStatementCollection—-коллекция комментариев; П CodeDirectiveCollection — коллекция директив кода; П codeExpressionCoiiection — коллекция выражений;

D CodeStatementCollection——- КОЛЛеКцИЯ КОДОВЫХ конструкций.

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

string commentText = "Комментарий, добавленный из сериализатора"; CodeCommentStatement comment =

new CodeCommentStatement(commentText); statements.Insert(0, comment);

Полный код сериализатора представлен в листинге 10.8. В результате работы этого сериализатора будет сгенерирован код, содержащий дополнительную строку комментария:

/ / Комментарий, добавленный из сериализатора

//

// testControll

//

this.testControll.Location = new System.Drawing.Point(109, 74); this.testControll.Name – "testControll";

this.testControll.Size = new System.Drawing.Size(75, 23);

this.testControl1.Tablndex = 0; this.testControll.TestProperty = "test-value"; this.testControll.Text = "testControll";

Аналогично, можно вмешиваться и в другие конструкции автоматически генерируемого кода.

Листинг 10.8. Класс, измениющии код сериализации компонента

using System;

using System. Col lections. Generic ; using System.Text;

using System.ComponentModel.Design.Serialization; using System.CodeDom;

namespace MyControl

{

public class TestSerializer : CodeDomSerializer {

public override object Deserialize{

IDes ignerSerializationManager manager, object codeObject)

{

il Получаем сериализатор CodeDomSerializer baseClassSerializer =

(CodeDomSerializer) manager.GetSerializer( typeof(TestControl).BaseType, typeof(CodeDomSerializer));

// Пока просто вызываем базовый десериализатор

return baseClassSerializer.Deserialize(manager, codeObject);

}

public override object Serialize(

IDes igne rS er i ali z at i onManager manage r, object value)

{

// Получаем сериализатор CodeDomSerializer baseClassSerializer =

(CodeDomSerializer) manager.GetSerializer( typeof(TestControl).BaseType, typeof(CodeDomSerializer));

// Получаем сериализуемый объект

object codeObject = baseClassSerializer.Serialize(manager, value);

// В принципе, объект может представляться разными способами. // Сейчас мы обрабатываем только случай представления // объекта набором строк кода, if (codeObject is CodeStatementCollection) (

// Последовательность строк кода CodeStatementCollection statements =

(CodeStatementCollection)codeObject;

// добавляем комментарий в самое начало кода string commentText =

"Комментарий, добавленный из сериализатора"; CodeCommentStatement comment -

new CodeCommentStatement(commentText); statements.Insert(0, comment);

}

return codeObject;

}

)

}

Литература:

Агуров П. В. C#. Разработка компонентов в MS Visual Studio 2005/2008. – СПб.: БХВ-Петербург, 2008. — 480 е.: ил.

По теме:

  • Комментарии