Как я могу сериализировать объект со свойством <string, object> Словаря?

В примере кода ниже, я получаю эту ошибку:

Элемент TestSerializeDictionary123. Клиент. Система CustomProperties vom Typ. Наборы. Универсальный. Словарь '2 [[Система. Строка, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089], [Система. Объект, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] не могут быть сериализированы, потому что он реализует IDictionary.

Когда я вынимаю свойство Dictionary, оно хорошо работает.

Как я могу сериализировать этот Клиентский объект со свойством словаря? Или что заменяющий тип для Словаря я могу использовать, который был бы сериализуемым?

using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.IO;
using System.Xml;
using System.Text;

namespace TestSerializeDictionary123
{
    public class Program
    {
        static void Main(string[] args)
        {
            List<Customer> customers = Customer.GetCustomers();

            Console.WriteLine("--- Serializing ------------------");

            foreach (var customer in customers)
            {
                Console.WriteLine("Serializing " + customer.GetFullName() + "...");
                string xml = XmlHelpers.SerializeObject<Customer>(customer);
                Console.WriteLine(xml);
                Console.WriteLine("Deserializing ...");
                Customer customer2 = XmlHelpers.DeserializeObject<Customer>(xml);
                Console.WriteLine(customer2.GetFullName());
                Console.WriteLine("---");
            }

            Console.ReadLine();
        }
    }

    public static class StringHelpers
    {
        public static String UTF8ByteArrayToString(Byte[] characters)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            String constructedString = encoding.GetString(characters);
            return (constructedString);
        }

        public static Byte[] StringToUTF8ByteArray(String pXmlString)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            Byte[] byteArray = encoding.GetBytes(pXmlString);
            return byteArray;
        }
    }

    public static class XmlHelpers
    {
        public static string SerializeObject<T>(object o)
        {
            MemoryStream ms = new MemoryStream();
            XmlSerializer xs = new XmlSerializer(typeof(T));
            XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8);
            xs.Serialize(xtw, o);
            ms = (MemoryStream)xtw.BaseStream;
            return StringHelpers.UTF8ByteArrayToString(ms.ToArray());
        }

        public static T DeserializeObject<T>(string xml)
        {
            XmlSerializer xs = new XmlSerializer(typeof(T));
            MemoryStream ms = new MemoryStream(StringHelpers.StringToUTF8ByteArray(xml));
            XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8);
            return (T)xs.Deserialize(ms);
        }
    }

    public class Customer
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Street { get; set; }
        public string Location { get; set; }
        public string ZipCode { get; set; }
        public Dictionary<string,object> CustomProperties { get; set; }

        private int internalValue = 23;

        public static List<Customer> GetCustomers()
        {
            List<Customer> customers = new List<Customer>();
            customers.Add(new Customer { Id = 1, FirstName = "Jim", LastName = "Jones", ZipCode = "23434" });
            customers.Add(new Customer { Id = 2, FirstName = "Joe", LastName = "Adams", ZipCode = "12312" });
            customers.Add(new Customer { Id = 3, FirstName = "Jack", LastName = "Johnson", ZipCode = "23111" });
            customers.Add(new Customer { Id = 4, FirstName = "Angie", LastName = "Reckar", ZipCode = "54343" });
            customers.Add(new Customer { Id = 5, FirstName = "Henry", LastName = "Anderson", ZipCode = "16623" });
            return customers;
        }

        public string GetFullName()
        {
            return FirstName + " " + LastName + "(" + internalValue + ")";
        }

    }
}
12
задан Edward Tanguay 13 January 2010 в 11:03
поделиться

6 ответов

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

DataContractSerializer xs = new DataContractSerializer(typeof (T));

вместо:

XmlSerializer xs = new XmlSerializer(typeof (T));

, которые решили проблему как DataContrattserializer поддерживают словарь.

Другое решение - это THS XML-сериализуемый универсальный словарь Обходной обходной путь также работает в приведенном выше примере, и есть длительное обсуждение по этой ссылке от людей, использующих его, может быть полезно для людей, работающих с этим вопросом.

14
ответ дан 2 December 2019 в 05:27
поделиться

Вот универсальный класс словаря, который знает, как сериализовать себя:

  public class XmlDictionary<T, V> : Dictionary<T, V>, IXmlSerializable {
    [XmlType("Entry")]
    public struct Entry {
      public Entry(T key, V value) : this() { Key = key; Value = value; }
      [XmlElement("Key")]
      public T Key { get; set; }
      [XmlElement("Value")]
      public V Value { get; set; }
    }
    System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() {
      return null;
    }
    void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) {
      this.Clear();
      var serializer = new XmlSerializer(typeof(List<Entry>));
      reader.Read();  // Why is this necessary?
      var list = (List<Entry>)serializer.Deserialize(reader);
      foreach (var entry in list) this.Add(entry.Key, entry.Value);
      reader.ReadEndElement();
    }
    void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) {
      var list = new List<Entry>(this.Count);
      foreach (var entry in this) list.Add(new Entry(entry.Key, entry.Value));
      XmlSerializer serializer = new XmlSerializer(list.GetType());
      serializer.Serialize(writer, list);
    }
  }
9
ответ дан 2 December 2019 в 05:27
поделиться

Вы не можете (не хватает всего себя самостоятельно, что ужасно); Serializer XML не будет иметь подсказку, что делать с объектом , так как он не включает в себя тип метаданных в формате провода. Один (Hacky) вариант будет трансформировать их все как строки для целей сериализации, но тогда у вас есть много дополнительного анализа (и т. Д.).

4
ответ дан 2 December 2019 в 05:27
поделиться

Как насчет того, чтобы пометить класс клиента в качестве DataContratt и его свойства, как DataMembers. DataContract Serializer сделает для вас сериализацию.

0
ответ дан 2 December 2019 в 05:27
поделиться

Вы можете использовать двоичную сериализацию вместо неё. (Убедитесь, что все Ваши классы помечены как [Сериализуемый] . Конечно, это не будет в формате XML, но Вы не перечислили это в качестве требования :)

.
1
ответ дан 2 December 2019 в 05:27
поделиться

Но почему только эти файлы 80?

Эти файлы имеют свойство svn: mergeinfo ; остальные нет. Когда отдельные файлы и вложенные папки проекта имеют это значение, оно называется «слиянием поддеревьев». Как только файл или папка имеют свойство «svn: mergeinfo», слияние обновляется при каждой операции слияния.

Если объединить только корень проекта и использовать последнюю версию SVN-клиента, слияние поддеревьев будет происходить редко. Только корневая папка ветвей проекта (например, /trunk , /branches/foo ) должна иметь свойство svn: mergeinfo .

edit : Если просто удалить слияние поддерева, то подрывная система не узнает, что слияние произошло. Таким образом, subversion может попытаться снова объединить эти версии, когда она автоматически выберет версии, подходящие для объединения (например, при выполнении svn merge без указания параметров -r или -c ). В худшем случае такая попытка слияния может вызвать некоторые ложные конфликты, что не является большой проблемой; просто разрешите их вручную.

update : Subversion 1,7 теперь обновляет слияние только тогда, когда это необходимо. Из примечаний к выпуску :

слияние больше не записывает слияние (описывающее слияние) в поддеревы (которые имеют свое собственное явное слияние), если поддерево не затрагивалось слиянием. Это должно значительно уменьшить количество ложных изменений свойств svn: mergeinfo для пользователей, имеющих большое количество поддеревьев с явным слиянием.

-121--3126712-

Это не поддерживается в DataGrid в наборе инструментов, и похоже, что не поддерживается при поставке DataGrid с .NET 4. Еще одна причина, по которой этот контроль не готов к использованию в производстве. Я бы пошел с одним из следующих вариантов:

  1. Свернуть собственную сетку с ListView/GridView
  2. Изменить исходный код DataGrid в инструментарии (это не должно быть слишком сложно, поскольку расширенный выбор уже поддерживается?)
  3. Найдите любые доступные коммерческие WPF DataGrid (обычно они добавляют огромный объем полезной функциональности)

Я согласен, что DataGrid должен поддерживать это, и я думаю, что вы должны подать ошибку/предложение для этого в любом случае. Может быть, еще не поздно попасть в .NET 4..:)

-121--3560056-

Я только что нашел эту запись в блоге Ракеша Раджана , в которой описывается одно возможное решение:

Переопределить StartSerialization, сделав тип реализующим класс System.Xml.Serialization.IXml. Определите, как объект должен быть сериализован в XML в методе WriteXml, и определите, как можно воссоздать объект из последовательности xml в методе ReadXml.

Но это не сработает, поскольку словарь содержит объект , а не определенный тип.

0
ответ дан 2 December 2019 в 05:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: