Обаружил противный баг в методе XmlSerializer.Deserialize.
Суть:
Если сериализован класс со строковыми полями содержащими escapе characters like \r\n\t то сериализуются они нормально, при десериализации вычитываются в поток тоже нормально, но как только мы делаем Deserialize для объекта то в стоковые поля попают с строки с искаженными последовательностями таких символов. Наблюдаются разные искажения но чаще всего исчезает символ \r или он же заменяется на \t.
Была мысль поотлаживать создаваемый слр код десериализатора, а смысл,
потеряю времени день два, может даже найду баг, а чего дальше с этим делать, собственный десериализатор для нескольких десятков классов как-то не вписывается в проект по срокам...
Это критичная часть проекта, и как обойти не представляю, вынимать строки через regexp... бред.
Здравствуйте, VVitaliy, Вы писали:
VV>Обаружил противный баг в методе XmlSerializer.Deserialize. VV>Суть: VV>Если сериализован класс со строковыми полями содержащими escapе characters like \r\n\t то сериализуются они нормально, при десериализации вычитываются в поток тоже нормально, но как только мы делаем Deserialize для объекта то в стоковые поля попают с строки с искаженными последовательностями таких символов. Наблюдаются разные искажения но чаще всего исчезает символ \r или он же заменяется на \t.
VV>Была мысль поотлаживать создаваемый слр код десериализатора, а смысл, VV>потеряю времени день два, может даже найду баг, а чего дальше с этим делать, собственный десериализатор для нескольких десятков классов как-то не вписывается в проект по срокам...
VV>Это критичная часть проекта, и как обойти не представляю, вынимать строки через regexp... бред.
VV>Есть у кого какие мнения по данному поводу?
Вот код:
Program.cs
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.Xml;
using System.Text;
using System.IO;
namespace XmlSerialization
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
string param = "a\rb\nc\td";
Class1 class1 = new Class1(param, param);
XmlSerializer ser = new XmlSerializer(typeof(Class1));
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
XmlWriterSettings xws = new XmlWriterSettings(); // Смотри сюда
xws.NewLineHandling = NewLineHandling.Entitize; // Особенно сюда
xws.Indent = true;
XmlWriter xw = XmlTextWriter.Create(sw, xws);
ser.Serialize(xw, class1);
string serializedObject = sb.ToString();
Console.WriteLine(serializedObject);
StringReader sr = new StringReader(serializedObject);
Class1 deserCalss1 = (Class1)ser.Deserialize(sr);
Console.WriteLine(string.Format("Original == deserialized is {0}", class1 == deserCalss1));
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
}
Class1.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
namespace XmlSerialization
{
public class Class1
{
public Class1()
{
}
public Class1(string name1, string name2)
{
_name1 = name1;
_name2 = name2;
}
private string _name1;
private string _name2;
[XmlAttribute]
public string Name1
{
get { return _name1; }
set { _name1 = value; }
}
[XmlElement]
public string Name2
{
get { return _name2; }
set { _name2 = value; }
}
public static bool operator ==(Class1 c1, Class1 c2)
{
return (c1._name1 == c2.Name1 && c1._name2 == c2.Name2);
}
public static bool operator !=(Class1 c1, Class1 c2)
{
return !(c1 == c2);
}
}
}
Здравствуйте, VVitaliy, Вы писали:
VV>Обаружил противный баг в методе XmlSerializer.Deserialize. VV>Суть: VV>Если сериализован класс со строковыми полями содержащими escapе characters like \r\n\t то сериализуются они нормально, при десериализации вычитываются в поток тоже нормально, но как только мы делаем Deserialize для объекта то в стоковые поля попают с строки с искаженными последовательностями таких символов. Наблюдаются разные искажения но чаще всего исчезает символ \r или он же заменяется на \t.
VV>Была мысль поотлаживать создаваемый слр код десериализатора, а смысл, VV>потеряю времени день два, может даже найду баг, а чего дальше с этим делать, собственный десериализатор для нескольких десятков классов как-то не вписывается в проект по срокам...
VV>Это критичная часть проекта, и как обойти не представляю, вынимать строки через regexp... бред.
VV>Есть у кого какие мнения по данному поводу?
XmlWriterSettings xws = new XmlWriterSettings(); // Смотри сюда
xws.NewLineHandling = NewLineHandling.Entitize; // Особенно сюда
Это только видимость — код строк все-равно портится (только по-другому). Правильно будет так десериализовать:
/// <summary>
/// Restores object's copy from XML-representation.
/// </summary>
/// <param name="xml">String with XML representation.</param>
/// <typeparam name="T">Type of object for restoring.</typeparam>
/// <returns>Object's instance.</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);
XmlTextReader xr = new XmlTextReader(reader);
xr.Normalization = false; // Смотри сюда
XmlSerializer sr = new XmlSerializer(typeof(T));
return (T)sr.Deserialize(xr);
}
Здравствуйте, KirillSon, Вы писали:
KS>Здравствуйте, MatFiz, Вы писали:
MF>>Вот код:
KS>
KS> XmlWriterSettings xws = new XmlWriterSettings(); // Смотри сюда
KS> xws.NewLineHandling = NewLineHandling.Entitize; // Особенно сюда
KS>
KS>Это только видимость — код строк все-равно портится (только по-другому). Правильно будет так десериализовать:
KS>
KS> /// <summary>
KS> /// Restores object's copy from XML-representation.
KS> /// </summary>
KS> /// <param name="xml">String with XML representation.</param>
KS> /// <typeparam name="T">Type of object for restoring.</typeparam>
KS> /// <returns>Object's instance.</returns>
KS> public static T XmlStr2Obj<T>(string xml)
KS> {
KS> if (xml == null)
KS> return default(T);
KS> if (xml == string.Empty)
KS> return (T)Activator.CreateInstance(typeof(T));
KS> StringReader reader = new StringReader(xml);
KS> XmlTextReader xr = new XmlTextReader(reader);
KS> xr.Normalization = false; // Смотри сюда
KS> XmlSerializer sr = new XmlSerializer(typeof(T));
KS> return (T)sr.Deserialize(xr);
KS> }
KS>
KS>Теперь строки возвращаются в исходном виде.
Да, хотелось бы узнать при каких условиях он портится, в своём проекте с активным использованием XML сериализации ничего плохого при использовании xws.NewLineHandling = NewLineHandling.Entitize не обраруживается...
Здравствуйте, MatFiz, Вы писали:
MF>Здравствуйте, KirillSon, Вы писали:
KS>>Это только видимость — код строк все-равно портится (только по-другому). Правильно будет так десериализовать:
MF>Как конкретно?
Сорри, посмотрел внимательнее — заменило \r\n на
\n. По-быстрому не заметил, что \n тоже вставляет, поэтому из двух вариантов выбрал тот, который выключает нормализацию.
Так что можно использовать и
xws.NewLineHandling = NewLineHandling.Entitize;
при записи
и
xr.Normalization = false;
при чтении
И то и то работает. Только продуцируют немного отличающиеся представления XML-строк.