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)

我想尝试将字符串更改为从字符串继承的自定义类,我可以为其配备一个名称,但问题是,不能从字符串继承......

4

6 回答 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.

但是,您可以通过将键值封装在您自己的类型中,然后XmlSerializer使用XmlTextAttribute(请参阅MSDN)控制输出来获得相同的结果:

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

在您的情况下,您将按如下方式使用该属性:

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

然后将此类型用作您的Dictionary. 哪个应该达到你想要的。

于 2010-07-28T12:34:39.567 回答
0

虽然它可能有点跑题了,但我需要问为什么要使用 XML 来序列化它?如果您只是想为将来保存对象状态,我建议您使用 JSON 而不是 XML。

一大好处是您可以轻松保存普通的 Dictionary 类,而无需编写任何特殊代码。有效负载也比 JSON 小得多,因此如果需要,它是一种很好的通过网络发送的格式。

Scott Gu 在此处提供了一些关于使用 JavascriptSerializer 的信息。我建议将其作为对象的扩展方法。然后你可以这样做:

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

如果您对此感兴趣,请告诉我,我可以发布我使用的扩展方法的代码。(请不要在工作中,我这里没有它们。)

于 2010-07-30T05:44:38.803 回答
0

不能说我已经使用了可序列化字典的实现,但如果你愿意尝试新事物,有一个鲜为人知的抽象类 KeyedCollection,它是完全可序列化的,支持基于键的访问,并且可以轻松实现为字典。

.Net 2.0 键控集合

于 2010-08-07T22:15:21.603 回答
0

由于您拥有源代码,因此您可以对其进行修改,以便查找 XML 属性(如果存在)。XML 属性家族没有什么特别之处——它们就像任何其他可以通过反射查找的属性一样。一旦你有了它,你就可以将新名称放入创建者和/或读取 XML 标记的代码中。您也可以只添加 2 个参数来显式覆盖标签名称,例如 ReadXml(myReader, "Tables", "Table") 并更改代码以遵循这些名称而不是默认值。不过必须切换到 C# :-)

于 2010-08-03T06:52:58.147 回答
0

您可以专门化 Dictionary 模板或从专门化中派生以根据需要进行序列化。

于 2010-07-16T11:26:29.300 回答
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;
    } 
}
于 2010-08-03T08:16:38.277 回答