2010-06-24 3 views
1

Это моя классовая структура:десериализации XML объекта со словарем

class DataItem 
{ 
    public string Id { get; set; } 
    public string Type { get; set; } 

    private Dictionary<string, DataProperty> properties = new Dictionary<string, DataProperty>(); 

    public Dictionary<string, DataProperty> Properties 
    { 
     get { return properties; } 
     set { properties = value; } 
    } 
} 

public class DataProperty 
{  
     public string Key { get; set; } 
     public string Value { get; set; } 
     public bool Required { get; set; } 
} 

Это XML я хочу использовать (Примечание: я могу изменить XML, если это необходимо):

<Data> 
    <DataItem> 
    <id>ph15</id> 
    <type>core</type> 
    <properties> 
     <DataProperty> 
     <key>size</key> 
     <value>50%</value> 
     <required>false</required> 
     </DataProperty> 
     <DataProperty> 
     <key>color</key> 
     <value>red</value> 
     <required>true</required> 
     </DataProperty> 
    </properties> 
    </DataItem> 
    <DataItem> 
    <id>ph234</id> 
    <type>core</type> 
    <properties> 
    </properties> 
    </DataItem> 
</Data> 

В конечном итоге XML следует загрузить в другой словарь:

private Dictionary<string, DataItem> Mydata; 
+0

Я предлагаю сопоставить xml в более прямые поля и использовать атрибуты для сериализации [de]. Затем у вас есть логика для [de] заполнения словаря из/в другую структуру данных. Также LINQ to xml может быть вашим другом. –

ответ

3

К сожалению, общие словари не являются XML-сериализуемыми.

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

В качестве альтернативы вы можете использовать что-то иное, кроме XmlSerializer (например, DataContractSerializer), которое поддерживает типы словарей.

Вот link to an article, который служит хорошим примером того, как изменить свой тип для поддержки XML-сериализации со словарем.

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

[XmlIgnore()] 
public Dictionary<string, DataProperty> Properties 
{ 
    set { properties = value; } 
    get { return properties ; } 
} 


[XmlArray("Stuff")] 
[XmlArrayItem("StuffLine", Type=typeof(DictionaryEntry))] 
public DictionaryEntry[] PropertiesList 
{ 
    get 
    { 
     //Make an array of DictionaryEntries to return 
     DictionaryEntry[] ret=new DictionaryEntry[Properties.Count]; 
     int i=0; 
     DictionaryEntry de; 
     //Iterate through Stuff to load items into the array. 
     foreach (KeyValuePair<string, DataProperty> props in Properties) 
     { 
      de = new DictionaryEntry(); 
      de.Key = props.Key; 
      de.Value = props.Value; 
      ret[i]=de; 
      i++; 
     } 
     return ret; 
    } 
    set 
    { 
     Properties.Clear(); 
     for (int i=0; i<value.Length; i++) 
     { 
      Properties.Add((string)value[i].Key, (DataProperty)value[i].Value); 
     } 
    } 
} 
+0

Мне понравился DataContract, и у меня есть другой вопрос: потому что класс DataItem представляет элемент в словаре Mydata, мне нужно создать другой класс, чтобы его обернуть? – ilann

+0

@ilann - Нет, вам не обязательно это делать. Yo должен иметь возможность сериализовать 'Mydata' напрямую, пока вы предоставляете необходимые метаданные для определения того, как члены будут сериализованы (например, узлы, атрибуты, cdata и т. Д.). – LBushkin

0

Что такое wr ong с использованием XmlSerializer?

+0

XmlSerializer не поддерживает типы словарей. – LBushkin

+0

Он не поддерживает IDictionary <,> – Aren

+0

А, да. Имеет смысл. –

0

Короткий ответ: Вы наклоняю

Это потому, что даже если вы можете представить себе схему сериализации, .NET Serializer не может гарантировать, что ключи повторно сериализованы будут иметь одинаковое значение хеш-функции.

Длинный ответ: Вы можете, но это очень много работы

Раствор для вас либо делать вручную сериализации всего объекта, или заменить словарь с простой Упаковочный собственности, которая надстроена IDictionary, но предоставляет его как список пар. (Вы можете преобразовать его позже, если вам это нужно.)

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

1

Я предлагаю вам использовать DataContractSerializer. Он поддерживает словари.

2

Я знаю, что на это был дан ответ раньше, но поскольку у меня есть очень краткий путь (код) для выполнения сериализации IDictionary с классом DataContractSerializer (используемый WCF, но его можно и нужно использовать в любом месте), я не мог удержаться it here:

public static class SerializationExtensions 
{ 
    public static string Serialize<T>(this T obj) 
    { 
     var serializer = new DataContractSerializer(obj.GetType()); 
     using (var writer = new StringWriter()) 
     using (var stm = new XmlTextWriter(writer)) 
     { 
      serializer.WriteObject(stm, obj); 
      return writer.ToString(); 
     } 
    } 
    public static T Deserialize<T>(this string serialized) 
    { 
     var serializer = new DataContractSerializer(typeof(T)); 
     using (var reader = new StringReader(serialized)) 
     using (var stm = new XmlTextReader(reader)) 
     { 
      return (T)serializer.ReadObject(stm); 
     } 
    } 
} 

Это прекрасно работает в .NET 4, а также должно работать в .NET 3.5, хотя я еще не тестировал его.Я сделал поток в строку, потому что мне было удобнее, хотя я мог бы ввести сериализацию более низкого уровня в Stream, а затем использовать его для сериализации для строк, но я склонен обобщать только тогда, когда это необходимо (так же, как преждевременная оптимизация - это зло , так что преждевременно обобщение ...)

Использование очень просто:

// dictionary to serialize to string 
Dictionary<string, object> myDict = new Dictionary<string, object>(); 
// add items to the dictionary... 
myDict.Add(...); 
// serialization is straight-forward 
string serialized = myDict.Serialize(); 
... 
// deserialization is just as simple 
Dictionary<string, object> myDictCopy = 
    serialized.Deserialize<Dictionary<string,object>>(); 

myDictCopy будет дословная копия myDict.

Вы также заметите, что общие методы, предоставляемые будут иметь возможность сериализации любого типа (в меру моих знаний), так как она не ограничивается интерфейсами IDictionary, это может быть действительно любое родового типа T.

Надеюсь, что это поможет кому-то!

1

Вы не можете, но другим способом сделать это было бы создание простого объекта, который сохраняет свойства Value и Key. Затем используйте List (Of theObject), и он должен работать. Но это зависит, если вы хотите только переносить данные ключа значения, потому что все остальные методы, которые являются частью словаря, недоступны.

Смежные вопросы