views:

343

answers:

6

Question: I use a serializable dictionary class, found at http://weblogs.asp.net/pwelter34/archive/2006/05/03/444961.aspx , to serialize a dictionary. Which works fine, but I run into an annoying problem.

      <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

When I serialize instances of the above class, as this, the created xml looks like this:

<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>

Which would be good if only I could figure out how to rename the key from <string> to something defined in an attribute

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

Basically something like the XmlArrayItem attribute, such as below, if (only) the dictionary were an array...

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

I wanted to try to change Of String to a custom class inherited from string, which I could equip with a name, but the problem is, one cannot inherit from string...

A: 

You could specialize the Dictionary template or derive from a specialization to serialize as you want.

onof
+1  A: 

If I'm reading your question correctly, you want to change your serialized output from this:

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

To something like this:

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

You also mention that one way you could achieve this would be to create your own type which inherited from System.String, which - as you also mention - obviously isn't possible because it's sealed.

You can however achieve the same result by encapsulating the key value in your own type, and then controlling the XmlSerializer output using an XmlTextAttribute (see MSDN):

By default, the XmlSerializer serializes a class member as an XML element. However, if you apply the XmlTextAttribute to a member, the XmlSerializer translates its value into XML text. This means that the value is encoded into the content of an XML element.

In your case you'd use the attribute as follows:

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

And then use this type as the key(s) to your Dictionary. Which should achieve what you want.

Dougc
A: 

Although it's probably somewhat off topic, I need to ask why use XML to serialize it? If you just want to save the object state for the future I would suggest JSON instead of XML.

One large benefit is you can easily save a normal Dictionary class without having to write any special code. The payload is also much smaller as JSON so it's a great format to send across the wire if needed.

Scott Gu has a bit of info about using the JavascriptSerializer here. I would suggest making it an extension method on object. Then you can do this:

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

If this is something your interested in let me know and I can post the code for the extension methods I use. (sry not at work and I don't have them with me here.)

Kelly
First, I'm limited to .NET 2.0, and second, the main problem is that dictionary is a generic type and NOT SERIALIZABLE (not in JSON either). I'm serializing to XML because XML is broader used, and better to read, if serialized from .NET 2.0.
Quandary
A: 

Since you have the source you can modify it so that it looks up XML attributes if they are present. There's nothign sacral about XML attribure family - the are just like any other attrib that can be looked up via reflection. Once yo u have that you can put new names into the code where in creater and/or reads XML tags. You can also just add 2 params to override tag names explicitly, like ReadXml(myReader, "Tables", "Table") and change the code to follow these names instead of defaults. Got to switch to C# though :-)

ZXX
A: 

Consider replacing Dictionary with KeyedCollection. It is serialized as a list, as a result it is smaller and XML node names are names of cTable properties/fields.

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

can't say that i've used that implementation of serializeable dictionary, but in case you're willing to try new things, there is a little known abstract class called KeyedCollection which is fully serializeable, supports key based access, and can be easily implemented as dictionary.

.Net 2.0 Keyed Collection

Sonic Soul