Сериализуемый словарь, как установить имя ключа? - PullRequest
7 голосов
/ 16 июля 2010

Вопрос: я использую сериализуемый класс словаря, найденный в 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>

Что было бы хорошо, если бы я только мог понять, как переименовать ключ из к чему-то определенному в атрибуте

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

В основном что-то вроде атрибута XmlArrayItem, например ниже, если (только) словарь был массивом ...

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

Я хотел попробовать изменить Of String на собственный класс, унаследованный от строки, который я мог бы снабдить именем, но проблема в том, что нельзя наследовать от строки ...

Ответы [ 6 ]

1 голос
/ 28 июля 2010

Если я правильно читаю ваш вопрос, вы хотите изменить ваш сериализованный вывод следующим образом:

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

Byпо умолчанию XmlSerializer сериализует члена класса как элемент XML.Однако если вы примените XmlTextAttribute к члену, XmlSerializer преобразует его значение в текст XML.Это означает, что значение закодировано в содержимом элемента XML.

В вашем случае вы должны использовать атрибут следующим образом:

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

И затем использовать этот типкак ключ (и) к вашему Dictionary.Который должен достичь того, что вы хотите.

0 голосов
/ 08 августа 2010

не могу сказать, что я использовал эту реализацию сериализуемого словаря, но на случай, если вы захотите попробовать что-то новое, есть малоизвестный абстрактный класс KeyedCollection, который полностью сериализуем, поддерживает доступ на основе ключей иможет быть легко реализовано в виде словаря.

.NET 2.0 Keyed Collection

0 голосов
/ 03 августа 2010

Попробуйте заменить словарь на KeyedCollection.Он сериализуется в виде списка, в результате он меньше и имена узлов XML являются именами свойств / полей cTable.

[Serializable]
[CollectionDataContract]
public class TablesCollection : KeyedCollection<string, cTable>
{
    protected override string GetKeyForItem(cTable item)
    {
        return item == null ? String.Empty : item.TableName;
    } 
}
0 голосов
/ 03 августа 2010

Поскольку у вас есть источник, вы можете изменить его, чтобы он просматривал атрибуты XML, если они присутствуют. В семействе атрибутов XML нет ничего особенного - они похожи на любой другой атрибут, который можно найти с помощью рефлексии. Как только вы это сделаете, вы можете вставить новые имена в код, где в создателе и / или читает теги XML. Вы также можете просто добавить 2 параметра для явного переопределения имен тегов, например ReadXml (myReader, «Tables», «Table»), и изменить код, следуя этим именам вместо значений по умолчанию. Должен переключиться на C #, хотя: -)

0 голосов
/ 30 июля 2010

Хотя это, вероятно, несколько не по теме, мне нужно спросить, зачем использовать XML для его сериализации? Если вы просто хотите сохранить состояние объекта на будущее, я бы предложил JSON вместо XML.

Одним из больших преимуществ является то, что вы можете легко сохранить обычный класс Dictionary без необходимости написания какого-либо специального кода. Полезная нагрузка также намного меньше, чем у JSON, поэтому это отличный формат для отправки по проводам, если это необходимо.

Скотт Гу имеет немного информации об использовании JavascriptSerializer здесь . Я бы предложил сделать это методом расширения объекта. Тогда вы можете сделать это:

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

Если это то, что вас интересует, дайте мне знать, и я могу опубликовать код для методов расширения, которые я использую. (извините, не на работе, и у меня их здесь нет.)

0 голосов
/ 16 июля 2010

Вы можете специализировать шаблон словаря или получить специализацию для сериализации, как вы хотите.

...