В примере кода ниже, я получаю эту ошибку:
Элемент 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 + ")";
}
}
}
В нашем приложении мы получили использование:
DataContractSerializer xs = new DataContractSerializer(typeof (T));
вместо:
XmlSerializer xs = new XmlSerializer(typeof (T));
, которые решили проблему как DataContrattserializer поддерживают словарь.
Другое решение - это THS XML-сериализуемый универсальный словарь Обходной обходной путь также работает в приведенном выше примере, и есть длительное обсуждение по этой ссылке от людей, использующих его, может быть полезно для людей, работающих с этим вопросом.
Вот универсальный класс словаря, который знает, как сериализовать себя:
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);
}
}
Вы не можете (не хватает всего себя самостоятельно, что ужасно); Serializer XML не будет иметь подсказку, что делать с объектом
, так как он не включает в себя тип метаданных в формате провода. Один (Hacky) вариант будет трансформировать их все как строки для целей сериализации, но тогда у вас есть много дополнительного анализа (и т. Д.).
Как насчет того, чтобы пометить класс клиента в качестве DataContratt и его свойства, как DataMembers. DataContract Serializer сделает для вас сериализацию.
Вы можете использовать двоичную сериализацию вместо неё. (Убедитесь, что все Ваши классы помечены как [Сериализуемый]
. Конечно, это не будет в формате XML, но Вы не перечислили это в качестве требования :)
Но почему только эти файлы 80?
Эти файлы имеют свойство svn: mergeinfo
; остальные нет. Когда отдельные файлы и вложенные папки проекта имеют это значение, оно называется «слиянием поддеревьев». Как только файл или папка имеют свойство «svn: mergeinfo», слияние обновляется при каждой операции слияния.
Если объединить только корень проекта и использовать последнюю версию SVN-клиента, слияние поддеревьев будет происходить редко. Только корневая папка ветвей проекта (например, /trunk
, /branches/foo
) должна иметь свойство svn: mergeinfo
.
edit : Если просто удалить слияние поддерева, то подрывная система не узнает, что слияние произошло. Таким образом, subversion может попытаться снова объединить эти версии, когда она автоматически выберет версии, подходящие для объединения (например, при выполнении svn merge
без указания параметров -r
или -c
). В худшем случае такая попытка слияния может вызвать некоторые ложные конфликты, что не является большой проблемой; просто разрешите их вручную.
update : Subversion 1,7 теперь обновляет слияние только тогда, когда это необходимо. Из примечаний к выпуску :
-121--3126712-слияние больше не записывает слияние (описывающее слияние) в поддеревы (которые имеют свое собственное явное слияние), если поддерево не затрагивалось слиянием. Это должно значительно уменьшить количество ложных изменений свойств svn: mergeinfo для пользователей, имеющих большое количество поддеревьев с явным слиянием.
Это не поддерживается в DataGrid в наборе инструментов, и похоже, что не поддерживается при поставке DataGrid с .NET 4. Еще одна причина, по которой этот контроль не готов к использованию в производстве. Я бы пошел с одним из следующих вариантов:
Я согласен, что DataGrid должен поддерживать это, и я думаю, что вы должны подать ошибку/предложение для этого в любом случае. Может быть, еще не поздно попасть в .NET 4..:)
-121--3560056-Я только что нашел эту запись в блоге Ракеша Раджана , в которой описывается одно возможное решение:
Переопределить StartSerialization, сделав тип реализующим класс System.Xml.Serialization.IXml. Определите, как объект должен быть сериализован в XML в методе WriteXml, и определите, как можно воссоздать объект из последовательности xml в методе ReadXml.
Но это не сработает, поскольку словарь содержит объект
, а не определенный тип.