TL,DR:我们已经在SQL数据库的一些表中序列化了一些数据。不幸的是,序列化技术为标记字符浪费了大量空间。我们找到了一种新的、更有效的方法:为了保持向后兼容性,采用以下逻辑安全吗->当序列化发生时,它总是使用新的、更有效的方式进行。当反序列化发生时,我们检查字符串是使用新的序列化格式还是旧的序列化格式-->然后使用适当的方法进行反序列化。这是稳健的吗?这个可以在生产中使用吗?这种方法没有任何微妙的问题吗?
问候。我正在开发一个与SQL数据库交互的应用程序。为了实现特定的业务需求,我们一直在数据库表的一个特殊列中序列化一些数据,该列的类型为ntext。基本上,在本列的每个单元格中,我们序列化一个"Attributo"对象的数组,因此typeof(T(是Attributo[]:
"归因"的定义如下:
public class Attributo
{
public virtual String Nome { get; set; }
public virtual String Valore { get; set; }
public virtual String Tipologia { get; set; }
}
-反序列化以读取实际值:
XMLUtilities.Deserialize<Attributo[]>(value));
序列化以将值存储在列中(对于每行..(:
XMLUtilities。序列化(attributes.ToArray(((;
这是helper类,它使用XmlSerializer对象:
public static class XMLUtilities
{
public static T Deserialize<T>(String xmlString)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (TextReader reader = new StringReader(xmlString))
{
return (T) serializer.Deserialize(reader);
}
}
public static String Serialize<T>(T xmlObject)
{
MemoryStream stream = new MemoryStream();
XmlSerializer serializer = new XmlSerializer(typeof(T));
XmlSerializerNamespaces xmlnsEmpty = new XmlSerializerNamespaces();
xmlnsEmpty.Add("", "");
serializer.Serialize(stream, xmlObject, xmlnsEmpty);
stream.Seek(0, SeekOrigin.Begin);
using (StreamReader reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
}
现在,这种技术的问题是它浪费了大量标记字符的空间。这是一个存储在数据库中的示例字符串:
<?xml version="1.0"?>
<ArrayOfAttributo>
<Attributo>
<Nome>Leakage_test_Time_prg1_p1</Nome>
<Valore>4</Valore>
<Tipologia>Single</Tipologia>
</Attributo>
<Attributo>
<Nome>Leakage_air_Volume_p1</Nome>
<Valore>14</Valore>
<Tipologia>Single</Tipologia>
</Attributo>
</ArrayOfAttributo>
因此,我们找到了一种更简洁的方法来序列化这些Attributo[],它会产生这种输出:
<ArrayOfA xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<A>
<N>Leakage_test_Time_prg1_p1</N>
<V>4</V>
<T>Single</T>
</A>
<A>
<N>Leakage_air_Volume_p1</N>
<V>14</V>
<T>Single</T>
</A>
</ArrayOfA>
然后,为了保持向后兼容性,这是核心问题我们实现了以下逻辑:
- 在序列化期间:
我们总是以新的、更简洁的方式序列化
- 反序列化期间:
我们检查字符串是否以:开头
<?xml version="1.0"?>
是否。如果是这样的话,这是一个旧条目,所以我们用旧的方式反序列化它。否则,我们将使用新格式进行反序列化。
我们通过这种方式装饰"归因"实现了这一点:
[DataContract(Name = "A", Namespace= "")]
public class Attributo
{
[DataMember(Name = "N")]
public virtual String Nome { get; set; }
[DataMember(Name = "V")]
public virtual String Valore { get; set; }
[DataMember(Name = "T")]
public virtual String Tipologia { get; set; }
}
通过对我们的序列化/反序列化方法执行以下更改,对于新的序列化技术,这些方法现在依赖于DataContractSerializer对象:
public static T Deserialize<T>(String xmlString)
{
//let's see if it's an old-style entry...
if (xmlString.StartsWith("<?xml version="1.0"?>rn<ArrayOfAttributo>"))
{
try
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (TextReader reader = new StringReader(xmlString))
{
return (T)serializer.Deserialize(reader);
}
}
catch { }
}
//..then it must be a new-style one
DataContractSerializer ser = new DataContractSerializer(typeof(T));
using (Stream s = _streamFromString(xmlString))
{
return (T) ser.ReadObject(s);
}
}
public static String Serialize<T>(T xmlObject)
{
MemoryStream stream1 = new MemoryStream();
DataContractSerializer ser = new DataContractSerializer(typeof(T));
ser.WriteObject(stream1, xmlObject);
stream1.Position = 0;
StreamReader sr = new StreamReader(stream1);
string xmlString = sr.ReadToEnd();
return xmlString;
}
private static Stream _streamFromString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
一切似乎都在使用这种方法,但我们希望在进一步操作之前评估每一种可能的风险。这在生产中使用安全吗
在反序列化旧条目时,还需要记住一件事:
- 以旧样式反序列化旧条目
- 序列化new中的旧条目
- 保存新样式序列化的旧条目,删除旧样式序列化的老条目
你可以走了。