пятница, ноября 24, 2006

X509Certificate2 и другие полезные вещи

Недавно в одном форуме проскакивал такой вопрос: "необходимо криптовать данные открытым ключем из сертификата юзера подключенного по SSL...".
По своему опыту работы с Framework 1.0 я считал, что это невозможно. Оказалось, что это не так. Здесь даже есть пример кода, как получить и использовать public key несимметричного алгоритма, который хранится в сертификате. Там несколько страниц жуткого кода.
Так вот, спешу вас обрадовать. В Framework 2.0 все стало гораздо лучше. Теперь задача шифрования открытым ключем из сертификата решается так:

// во первых SSL сертификат можно теперь получить вот так
X509Certificate2 cer = new X509Certificate2(request.ServicePoint.Certificate);
String str = "secret";
// ну а следующая строчка заменяет целые страницы зубодробительного кода
RSACryptoServiceProvider alg = (RSACryptoServiceProvider)cer.PublicKey.Key;
byte[] crypted = alg.Encrypt(Encoding.UTF8.GetBytes(str), false);

Кроме этого, появилась возможность работать с хранилищем сертификатов Windows через класс X509Store.
А вот обработка ошибок, связанных с сертификатами, как была неудобной, так и осталась. Интерфейс ICertificatePolicy объявили устаревшим, а вместо него там же ввели новый делегат ServicePointManager.ServerCertificateValidationCallback тоже статический.
Зато порадовал класс X509Certificate2UI. Его метод DisplayCertificate() отображает стандартное окно свойств сертификата!

вторник, ноября 07, 2006

Билл Гейтс в Москве

Сегодня Билл Гейтс должен приехать в Москву. Говорят, что он едет на Microsoft Бизнес Форум и будет представлять новые продукты Office 2007 и Vista, продажи которых начнутся в ближайшие месяцы. Но, я не ошибусь, если скажу, что российское IT сообщество волнует совсем другой вопрос. Всех волнует, откроет ли, наконец, Microsoft центр разработок в России? Или, если сформулировать вопрос по другому, почему Microsoft до сих пор этого не сделала? Примечательно, что на недавно открывшемся сервисе Ask Microsoft Executives (Задай вопрос руководству Microsoft) за более чем месяц его существования появился всего лишь один вопрос. Догадайтесь какой! :)
И еще одна деталь. Вместе с Гейтсом едет Крейг Манди, глава научно-исследовательского и стратегического направления в Microsoft. Может, наконец, мы получим ответ на наш вопрос?

пятница, ноября 03, 2006

Microsoft разрешила нам ковыряться в коде

Вот пришла новость. Microsoft и Novell заключили своего рода соглашение о не нападении. На фотографии довольные Рон Ховсепиан и Стив Балмер о чем то увлеченно шепчутся. О чем конкретно договорились важные персоны не совсем понятно. Вроде того, что обе компании не будут препятствовать тому, что-бы их операционные системы исполнялись на одном компьютере :).
Позабавила меня цитата из обращения компаний: "Novell получила нерушимое обещание от Microsoft позволить частным и некоммерческим программистам беспрепятственно продолжать разработку программ с открытым исходным кодом, не опасаясь патентных исков от Microsoft. Да, это так. Microsoft хочет, чтобы вы продолжали ковыряться в кодах". Ну - спасибо. Развеселили.
А еще порадовало то, что Novell все еще жива. Я правда всегда думал об этой компании, как об авторе незабвеной ОС Netware, с которой много лет назад мне провелось провести не одни веселые выходные на работе. Ан нет. Нынче Novell двигает в массы Linux. SUSE Linux, чужой, по сути, для Novell продукт.
Неисповедимы пути Господни. Когда-то могущественная Novell диктовала моду на рынке серверных операционок. Novell обязаны своим расцветом Ethernet и своим провалом Token Ring. У Novell появилась первые службы каталогов, и рапределенной печати. Все это было в то время когда Windows была свего лишь убогой псевдо многозадачной оконной оболочкой, запускаемой из под ДОС.
Ну и где сегодня тот Novell?


Ссылки по теме:
Novell
Novell NetWare
Microsoft

среда, ноября 01, 2006

Xml Serialization

Xml сериализация в .Net Framework 2.0 tips & tricks



Вступление


В данной статье рассматриваются различные практические аспекты использования Xml сериализации в .Net Framework. В статье мало текста, зато много примеров кода и Xml.


Что такое Xml сериализация.


Xml широко используется в .Net приложениях, и .Net framework предоставляет богатые возможности по работе с Xml. Среди них: поддержка Xml DOM (System.Xml.XmlDocument), последовательное чтение - запись Xml, поддержка xPath и xQuery, поддержка XSLT, богатые возможности DataSet по работе с Xml и, наконец, Xml сериализация.


Xml сериализация позволяет представлять Xml в виде иерархии классов, и наоборот, данные классов представлять в виде Xml. Когда стоит использовать Xml сериализацию? Мое мнение таково. Во всех случаях, когда нам заранее известна структура Xml, с которым предстоит работать, следует использовать Xml сериализацию.


Как работает Xml сериализация.


При Xml сериализации, сериализуются все открытые поля и свойства класса. Кроме того, открытые свойства должны иметь аксессоры get и set, а сам класс должен иметь конструктор по умолчанию без параметров. Рассмотрим класс:




public class DataClass
{
public DataClass(){}
public string ID = Guid.NewGuid().ToString();
public string Name = "Just Name";
public Decimal Count = 10;
public DateTime Date = DateTime.Now;
}


Его мы будем использовать во всех дальнейших примерах сериализации и десериализации.


Для сериализации нам надо создать экземпляр класса XmlSerializer, предав в качестве параметра конструктора тип сериализуемого класса. Следующий код демонстрирует сериализацию объекта нашего класса DataClass:



DataClass obj = new DataClass();
// создаем сериалайзер
XmlSerializer sr = new XmlSerializer(obj.GetType());
// создаем writer, в который будет происходить сериализация
StringBuilder sb = new StringBuilder();
StringWriter w = new StringWriter(sb, System.Globalization.CultureInfo.InvariantCulture);
// сериализуем
sr.Serialize(w,obj);
// получаем строку Xml
string xml = sb.ToString();
Console.WriteLine(xml);


В результате получаем вот такой Xml:



<?xml version="1.0" encoding="utf-8"?>
<DataClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ID>34332413-e70f-44f7-b35c-b34c47812dbc</ID>
<Name>Just Name</Name>
<Count>10</Count>
<Date>2006-10-30T12:35:20.3110319+03:00</Date>
</DataClass>


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



// создаем reader
StringReader reader = new StringReader(xml);
// создаем XmlSerializer
XmlSerializer dsr = new XmlSerializer(typeof(DataClass));
// десериализуем
DataClass clone = (DataClass)dsr.Deserialize(reader);


Управлять, тем как свойства и поля объекта отображаются на элементы Xml, можно при помощи атрибутов, которые содержатся в пространстве имен System.Xml.Serialization. Допустим, мы хотим, чтобы в результирующем Xml корневой элемент назывался <Data>, поля “ID”, “Name” сериализовались Xml атрибутами, поле “Count” соответствовало Xml элементу <Reserved>, а поле “Date”, вообще не попадало в результирующий Xml. Для этого расставим соответствующие атрибуты:



    [XmlRoot("Data")] // изменим имя корневого элемента
public class DataClass
{
public DataClass(){}

[XmlAttribute] // сериализуем в xml атрибут
public string ID = Guid.NewGuid().ToString();

[XmlAttribute] // сериализуем в xml атрибут
public string Name = "Just Name";

[XmlElement("Reserved")] // изменим имя xml элемента
public Decimal Count = 10;

[XmlIgnore] // не будет сериализоваться
public DateTime Date = DateTime.Now;
}


Результирующий Xml теперь выглядит так:





<?xml version="1.0" encoding="utf-8"?>
<Data xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ID="cc340d5e-4c80-4fe5-9c3d-e49f64e26b22" Name="Just Name">
<Reserved>10</Reserved>
</Data>



Как видно из представленного кода, использовать Xml сериализацию не сложно. Но все же попробуем облегчить себе жизнь. Для этого вынесем код, ответственный за сериализацию в отдельный класс утилиту:



public class XmlUtility
{
/// <summary>
/// Сериализует объект в строку XML
/// </summary>
public static string Obj2XmlStr(object obj, string nameSpace)
{
if (obj == null) return string.Empty;
XmlSerializer sr = new XmlSerializer(type);
StringBuilder sb = new StringBuilder();
StringWriter w = new StringWriter(sb, System.Globalization.CultureInfo.InvariantCulture);
sr.Serialize(
w,
obj,
new XmlSerializerNamespaces(
new XmlQualifiedName[]
{
new XmlQualifiedName("", nameSpace)
}
));
return sb.ToString();
}

/// <summary>
/// Сериализует объект в строку XML
/// </summary>
public static string Obj2XmlStr(object obj)
{
if (obj == null) return string.Empty;
XmlSerializer sr = new XmlSerializer(obj.GetType());
StringBuilder sb = new StringBuilder();
StringWriter w = new StringWriter(sb, System.Globalization.CultureInfo.InvariantCulture);
sr.Serialize(
w,
obj,
new XmlSerializerNamespaces( new XmlQualifiedName[] { new XmlQualifiedName(string.Empty) } ) );
return sb.ToString();
}

/// <summary>
/// Десериализует строку XML в объект заданного типа
/// </summary>
/// <param name="xml"></param>
/// <param name="type"></param>
/// <returns></returns>
public static T XmlStr2Obj<T>(string xml)
{
if (xml == null) return default(T);
if (xml == string.Empty) return (T)Activator.CreateInstance(typeof(T));

StringReader reader = new StringReader(xml);
XmlSerializer sr = new XmlSerializer(typeof(T));//SerializerCache.GetSerializer(type);
return (T)sr.Deserialize(reader);
}
}


Назначение метода Obj2XmlStr(object obj, string nameSpace) я объясню несколько позже. Теперь наш код для сериализации и десериализации объекта сократился в несколько раз:



DataClass obj = new DataClass();
string xml = XmlUtility.Obj2XmlStr(obj);
Console.WriteLine(xml);
DataClass clone = XmlUtility.XmlStr2Obj<DataClass>(xml);


Полный код класса XmlUtility вы найдете в исходном коде, прилагаемом к статье.


Namespce и сериализация.


Когда мы используем для сериализации метод XmlUtility.Obj2XmlStr(obj), мы можем заметить, что результирующий xml получается несколько более компактным чем прежде потому, что из него исчезли стандартные префиксы нэймспейсов XmlSchema - xsd и XmlSchema Instance - xsi :



<?xml version="1.0" encoding="utf-8"?>
<Data ID="078ce191-f781-4052-93fd-766309c2abaa" Name="Just Name">
<Reserved>10</Reserved>
</Data>


Произошло это из-за использования перегруженного метода SmlSerializer.Serialize(), в котором явно указывается перечень используемых Xml namespace – ов (пустой в данном конкретном случае).


Есть в нашей утилите и метод, позволяющий явно задать namespace для сериализации - Obj2XmlStr(object obj, string nameSpace). Учет Xml namespace при сериализации очень важен. Рассмотрим следующий пример:



DataClass obj = new DataClass();
// зададим явно XmlNamespace при сериализации
string xml = XmlUtility.Obj2XmlStr(obj, "urn:MyDataClass");
Console.WriteLine(xml);
DataClass clone = XmlUtility.XmlStr2Obj<DataClass>(xml);


При попытке десериализации полученного Xml обратно в объект, в пятой строке мы получим исключение:



<?xml version="1.0" encoding="utf-8"?>
<Data xmlns="urn:MyDataClass" ID="e46917f4-691a-4a7f-9f0b-d9be5e018a1f" Name="Just Name">
<Reserved>10</Reserved>
</Data>

System.InvalidOperationException : <Data xmlns='urn:MyDataClass'> was not expected.


Дело в том, что сериалайзеру не было никаких указаний по поводу Xml namespace для данного класса. И появление объявления namespace по умолчанию xmlns="urn:MyDataClass" становится непреодолимой преградой на пути десериализации Xml в объект. Явно указать, какой namespace надо использовать сериалайзеру можно в атрибуте XmlRootAttribute. Например:



[XmlRoot("Data", Namespace=DataClass.XmlNamespace )]
public class DataClass
{
public const string XmlNamespace = "urn:MyDataClass";


После этих изменений в коде, ошибка времени выполнения при десериализации пропадает и код, приведенный ранее, выполняется.


А что будет, если теперь при сериализации не указывать namespace явно, а вызвать



string xml = XmlUtility.Obj2XmlStr(obj);


Результирующий Xml опять изменится, но сериализация и десериализация выполнятся без ошибок:



<?xml version="1.0" encoding="utf-8"?>
<q1:Data ID="1458c25e-4356-4df5-b918-a44c9bf5e4b0" Name="Just Name" xmlns:q1="urn:MyDataClass">
<q1:Reserved>10</q1:Reserved>
</q1:Data>


Мы видим, что все xml элементы получили префикс “ql”. Произошло это из-за того, что namespace "urn:MyDataClass" объявлен в атрибуте XmlRoot нашего класса, а при сериализации он не был задан в качестве namespace по умолчанию. Таких ситуаций следует избегать. Лучше, либо вообще не использовать namespace, либо задавать их явно в качестве namespace по умолчанию, что позволяет избежать использования префиксов в Xml. Nmespace можно задать не только для класса, но и для каждого элемента в отдельности (но без нужды лучше этого не делать). Кроме того, при разработке крупных систем, может оказаться, что для разных классов заданы разные namespace, и тут уже не избежать появления префиксов имен в результирующем Xml. Поэтому данному вопросу необходимо постоянно уделять внимание.


Сериализация массивов и коллекций.


Рассмотрим некоторые особенности сериализации массивов и коллекций. Для этого добавим в объявление нашего сериализуемого класса поле в виде массива строк:



[XmlRoot("Data", Namespace=DataClass.XmlNamespace )]
public class DataClass
{
...
//массив строк
public string[] Lines = new string[] { "Line one", "Line two", "Line three" };
}


После сериализации мы получим следующий Xml



<?xml version="1.0" encoding="utf-8"?>
<Data ID="cafaafbf-fa51-47d5-a921-0ffeb8a7e345" Name="Just Name" xmlns="urn:MyDataClass">
<Reserved>10</Reserved>
<Lines>
<string>Line one</string>
<string>Line two</string>
<string>Line three</string>
</Lines>
</Data>


По умолчанию, массив (коллекция) сериализуется в xml элемент с именем поля или свойства, в который вложены элементы, входящие в массив. Возможно, это не совсем тот Xml который вы хотели бы увидеть. Управлять сериализацией массива помогают атрибуты XmlArray, XmlArrayItem, и XmlElement. Давайте рассмотрим эти возможности подробнее. Меня, например, не устраивает то, что элементы массива называются <string>. Мне нужно, чтобы элементы назывались <Line>. Достигается это при помощи атрибута XmlArrayItem над полем Lines. Если же нам надо изменить название элемента <Lines>, то для этого используем атрибут XmlArray:



[XmlArray("Specification")]
[XmlArrayItem("Line")]
public string[] Lines = new string[] { "Line one", "Line two", "Line three" };


Результирующий Xml изменился:



<?xml version="1.0" encoding="utf-8"?>
<Data ID="64a2c310-fa58-4a28-9cb2-7652625b28fc" Name="Just Name" xmlns="urn:MyDataClass">
<Reserved>10</Reserved>
<Specification>
<Line>Line one</Line>
<Line>Line two</Line>
<Line>Line three</Line>
</Specification>
</Data>


Ну, и, наконец, часто бывают ситуации, когда мы хотели бы вообще избавиться от элемента <Specification> и получить вот такой xml:



<?xml version="1.0" encoding="utf-8"?>
<Data ID="58f7271e-d6b2-4c7f-b3f3-334d8f087f09" Name="Just Name" xmlns="urn:MyDataClass">
<Reserved>10</Reserved>
<Line>Line one</Line>
<Line>Line two</Line>
<Line>Line three</Line>
</Data>


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



[XmlElement("Line")]
public string[] Lines = new string[] { "Line one", "Line two", "Line three" };


Подобно массивам сериализуются коллекции. Например мы можем добавить в объявление DataClass поле типа ArrayList и заполнить его различными значениями:



public class DataClass
{
...
// коллекция
public ArrayList List = new ArrayList();
}

// создаем экземпляр и наполняем коллекцию List различными объектами
DataClass obj = new DataClass();
obj.List.Add(new DataClass());
obj.List.Add("This is a string");
string xml = XmlUtility.Obj2XmlStr(obj, DataClass.XmlNamespace);
Console.WriteLine(xml);


Сериалайзер справился с поставленной задачей и выдал вот такой xml:



<?xml version="1.0" encoding="utf-8"?>
<Data ID="b1d70646-0985-424a-b87b-1e910173c9e5" Name="Just Name" xmlns="urn:MyDataClass">
<Reserved>10</Reserved>
<Line>Line one</Line>
<Line>Line two</Line>
<Line>Line three</Line>
<List>
<anyType d3p1:type="DataClass" ID="0a57f292-7a0e-479d-93e2-6c42fa019025" Name="Just Name" xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance">
<Reserved>10</Reserved>
<Line>Line one</Line>
<Line>Line two</Line>
<Line>Line three</Line>
<List />
</anyType>
<anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d3p1:type="q1:string" xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance">This is a string</anyType>
</List>
</Data>


Элементы списка сериализуются в xml элементы <anyType>, в которые добавляется дополнительная информация о типе каждого элемента. Однако, подобная сериализация, это не самая лучшая идея, поверьте. Особенно если данный Xml предназначен для обмена данными с другой системой. Дело в том, что в нашем случае схема результирующего Xml расширяется в runtime в зависимости от типа элементов, добавляемых в коллекцию. Далеко не все системы смогут правильно обработать такой Xml. По возможности, следует избегать использования не типизированных коллекций. Совсем другое дело - использование Generic коллекций. Модифицируем наш DataClass следующим образом, вместо ArrayList используем List<DataClass>:



public class DataClass
{
...
//public ArrayList List = new ArrayList();
public List<DataClass> List = new List<DataClass>();
}


Результирующий Xml выглядит теперь вот так:



<?xml version="1.0" encoding="utf-8"?>
<Data ID="13688ff2-c55f-45d7-8498-750a3e5df1d1" Name="Just Name" xmlns="urn:MyDataClass">
<Reserved>10</Reserved>
<Line>Line one</Line>
<Line>Line two</Line>
<Line>Line three</Line>
<List>
<DataClass ID="c250a091-4d99-40eb-a870-201f6130579b" Name="Just Name">
<Reserved>10</Reserved>
<Line>Line one</Line>
<Line>Line two</Line>
<Line>Line three</Line>
<List />
</DataClass>
</List>
</Data>


Как мы можем убедиться из xml исчезли элементы <anyType>, потому что тип элементов коллекции известен заранее.


Xml Сериализация и наследование


У Xml сериализации непростые отношения с объектным наследованием. Рассмотрим пример. Объявим класс ChildClass – наследник DataClass, а в самом DataClass объявим поле Child:



public class DataClass
{
...
[XmlElement]
public DataClass Child;
...
}

public class ChildClass : DataClass
{
public string ParentName;
}


А теперь попробуем воспользоваться полиморфизмом, и присвоим DataClass.Child объект типа ChildClass



DataClass obj = new DataClass();
obj.Child = new ChildClass();
string xml = XmlUtility.Obj2XmlStr(obj, DataClass.XmlNamespace);
Console.WriteLine(xml);


Результат будет плачевный. XmlSerializer не приветствует наши опыты с полиморфизмом и отказывается сериализовать наши объекты, выдавая при этом исключение:



UnitTest.XmlUtilityTest.SerializeTest : System.InvalidOperationException : There was an error generating the XML document.
----> System.InvalidOperationException : The type UnitTest.ChildClass was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.


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



[XmlRoot("Data", Namespace=DataClass.XmlNamespace )]
[XmlInclude(typeof(ChildClass))]
public class DataClass
{
public const string XmlNamespace = "urn:MyDataClass";
public DataClass(){}

[XmlElement]
public DataClass Child;
...
}
[XmlType(Namespace=DataClass.XmlNamespace)]
public class ChildClass : DataClass
{
public string ParentName;
}


Причем при появлении новых наследников, мы должны добавлять новые XmlInclude над базовым классом. Если же исходный код базового класса нам не доступен, то мы попадаем в довольно сложную ситуацию. Предположим мы не можем изменять описание базового класса DataClass, потому что у нас нет доступа к его исходному коду. У нас объявлен еще один его наследник CrandChildClass:DataClass, и мы присваиваем полю DataClass.Child экземпляр этого нового типа. Сериализация в этом случае не возможна. Но выход, все-таки есть, хотя и довольно запутанный. Специально для этого случая существует тип XmlAttributeOverrides и конструктор в XmlSerializer, принимающий этот тип. Суть его использования состоит в том, что с его помощью мы в runtime можем переопределить атрибуты, управляющие xml сериализацией, заданные в исходном коде.


Вот пример:



DataClass obj = new DataClass();
// присваиваем значение наследника для которого не был определен XmlInclude
obj.Child = new GrandChildClass();
// переопределяем атрибуты сериализации
XmlAttributes attrs = new XmlAttributes();
XmlElementAttribute attr = new XmlElementAttribute();
attr.ElementName = "GrandChildClass";
attr.Type = typeof(GrandChildClass);
attrs.XmlElements.Add(attr);
XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();
attrOverrides.Add(typeof(DataClass), "Child", attrs);
// используем специальный конструктор
XmlSerializer sr = new XmlSerializer(typeof(DataClass), attrOverrides);
StringBuilder sb = new StringBuilder();
StringWriter w = new StringWriter(sb, System.Globalization.CultureInfo.InvariantCulture);
sr.Serialize(w,obj); // успех
string xml = sb.ToString();
Console.WriteLine(xml);


Видите, сколько кода пришлось написать, только для того чтобы сделать возможным сериализацию вот этой строки: obj.Child = new GrandChildClass(); Причем надо учитывать, что это всего лишь пример. В этом коде мы не сможем сериализовать obj если присвоим obj.Child значение любого другого типа кроме GrandChildClass. Для этого нам надо будет добавить в XmlAttributeOverrides переопределения атрибутов “Child” для всех остальных типов, которые предполагается использовать.




Вопросы производительности.


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



/// <summary>
/// Кэш для используемых сериалайзеров
/// </summary>
internal class SerializerCache
{
private static Hashtable hash = new Hashtable();
public static XmlSerializer GetSerializer(Type type)
{
XmlSerializer res = null;
lock(hash)
{
res = hash[type.FullName] as XmlSerializer;
if(res == null)
{
res = new XmlSerializer(type);
hash[type.FullName] = res;
}
}
return res;
}
}


Этот маленький класс сотворил чудо. Везде где мне нужен экземпляр XmlSerializer, вместо конструктора я использую SerializerCache.GetSerializer(). В результате производительность операций xml сериализации выросла на порядок.


Во Framework 2.0 разработчики отчасти поправили положение. Теперь XmlSerializer сам кэширует создаваемые им сборки, правда происходит это только при использовании конструкторов System.Xml.Serialization.XmlSerializer(Type) System.Xml.Serialization.XmlSerializer(Type,String).


Я решил проверить, имеет ли теперь смысл использовать предложенный мной класс SerializerCache? Для этого выполним тест. Сначала сериализуем 1000 объектов DataClass создавая каждый раз новый экземпляр XmlSerialize. А затем сериализуем 1000 объектов DataClass используя SerializerCache (т.е. используя один экземпляр XmlSerializer). Измерим время, затраченное на два теста:



Direct serialization time 00:00:02.2574448
Cache serialization time 00:00:00.3135340


Как видно, кэширование экземпляров XmlSerializer по прежнему дает почти семикратный выигрыш во времени исполнения. Поэтому я рекомендую использовать эту технику, если ваше приложение активно использует Xml сериализацию.




Исходный код к статье