可序列化字典,如何设置键名?

7
问题:我使用一个序列化字典类,可以在http://weblogs.asp.net/pwelter34/archive/2006/05/03/444961.aspx找到,用于序列化一个字典。这个方法很好用,但是我遇到了一个烦人的问题。
      <System.Xml.Serialization.XmlRoot("DataBase")> _
    Public Class cDataBase
        <System.Xml.Serialization.XmlNamespaceDeclarations()> _
        Public ns As New System.Xml.Serialization.XmlSerializerNamespaces()


        <System.Xml.Serialization.XmlElement("Tables")> _
        Public Tables1 As New SerializableDictionary(Of String, cTable)


    End Class ' cDataBase

当我序列化上述类的实例时,如下所示, 创建的xml如下:
<Tables>
<item>
  <key>
    <string>MyTable</string>
  </key>
  <value>
    <Table CreationDate="0001-01-01T00:00:00" LastModified="0001-01-01T00:00:00">
      <Columns>
        <Column Name="PrimaryKeyName">
          <DataType>Uniqueidentifier</DataType>
          <Length>36</Length>
        </Column>
      </Columns>
      <Rows>
        <Row>
          <Item>Reihe1</Item>
          <Item>Reihe2</Item>
          <Item>Reihe3</Item>
        </Row>
        <Row>
          <Item>Reihe1</Item>
          <Item>Reihe2</Item>
          <Item>Reihe3</Item>
        </Row>

如果我能弄清楚如何将键名从<string>重命名为某个属性中定义的内容,那就太好了。

  <key>
    <string>MyTable</string>
  </key>

基本上就像XmlArrayItem属性一样,例如下面的代码,如果(只有)字典是数组,则...

        <System.Xml.Serialization.XmlArray("Tables")> _
        <System.Xml.Serialization.XmlArrayItem("Table")> _
        Public Tables As New List(Of cTable)

我想尝试将字符串更改为从自定义类继承的字符串,该类可以具有名称,但问题是,无法从字符串继承...

6个回答

1
如果我正确理解了你的问题,你想要将序列化输出从这个改变为:
<Tables>
  <item>
    <key>
      <string>MyTable</string>
    </key>
    <value>
      <!-- snip -->
    </value>
  </item>
</Tables>

变成这样:

<Tables>
  <item>
    <key>
      <TableId>MyTable</TableId>
    </key>
    <value>
      <!-- snip -->
    </value>
  </item>
</Tables>

你还提到了一种实现方式,即创建一个继承自System.String的自定义类型,但正如你所提到的,这是不可能的,因为它是sealed的。

然而,你可以通过封装键值在自己的类型中,并使用XmlTextAttribute(参见MSDN)控制XmlSerializer输出来实现相同的结果:

默认情况下,XmlSerializer将类成员序列化为XML元素。但是,如果将XmlTextAttribute应用于成员,则XmlSerializer将其值转换为XML文本。这意味着该值被编码到XML元素的内容中。

在你的情况下,你可以按照以下方式使用该属性:

public class TableId
{
    [XmlText]
    public string Name
    {
        get;
        set;
    }
}

然后将此类型用作您的字典的键。这样应该可以实现您想要的功能。


0

虽然这可能有点离题,但我需要问一下为什么使用XML进行序列化?如果您只想保存对象状态以备将来使用,我建议使用JSON而不是XML。

一个很大的好处是,您可以轻松保存普通的Dictionary类,而无需编写任何特殊代码。与XML相比,JSON的有效载荷也要小得多,因此如果需要在网络上发送数据,则是一个非常好的格式。

Scott Gu关于使用JavascriptSerializer的一些信息 here。我建议将其作为对象的扩展方法。然后,您可以这样做:

Dictionary<int, string> myDict = new Dictionary<int,string>();
myDict.Add(10,"something");
string jsonData = myDict.ToJSON();

如果您对此感兴趣,请告诉我,我可以发布我使用的扩展方法的代码。(抱歉,我现在不在工作岗位上,这里没有我的代码。)

首先,我受限于.NET 2.0。其次,主要问题是字典是一种泛型类型,而且不可序列化(JSON也不行)。我正在序列化为XML,因为XML更广泛使用,并且如果从.NET 2.0序列化,则更易于阅读。 - Stefan Steiger

0

考虑使用KeyedCollection替换Dictionary。它被序列化为列表,因此它更小,XML节点名称是cTable属性/字段的名称。

[Serializable]
[CollectionDataContract]
public class TablesCollection : KeyedCollection<string, cTable>
{
    protected override string GetKeyForItem(cTable item)
    {
        return item == null ? String.Empty : item.TableName;
    } 
}

0

由于您拥有源代码,因此可以修改它,以便在存在XML属性时查找它们。 XML属性族没有什么神圣的地方-它们就像可以通过反射查找的任何其他属性一样。 一旦您拥有了这个功能,您就可以将新名称放入代码中,在创建和/或读取XML标记时使用它们。 您还可以只添加2个参数来显式覆盖标记名称,例如ReadXml(myReader,“Tables”,“Table”),并更改代码以遵循这些名称而不是默认值。 不过,必须切换到C#:-)


0

我不能说我曾经使用过可序列化字典的这种实现方式,但是如果你愿意尝试新事物,有一个鲜为人知的抽象类叫做KeyedCollection,它完全可序列化,支持基于键的访问,并且可以很容易地实现为字典。

.Net 2.0 Keyed Collection


0

你可以专门用字典模板或者从专门化派生出来,以你想要的方式进行序列化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接