简体   繁体   English

使用字典将xml反序列化为对象

[英]Deserializing xml to object with dictionary

This is my class structure: 这是我的课程结构:

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

This is XML I want to use ( NOTE: I can change the xml if needed ): 这是我要使用的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>

Eventually XML should be loaded into another dictionary: 最终,XML应该加载到另一个字典中:

private Dictionary<string, DataItem> Mydata;

Unfortunately, generic dictionaries are not xml serializable. 不幸的是,通用词典无法xml序列化。

The workaround is to greate a separate field specifically to support serialization that exposes the elements of the dictionary as a list of key/value pairs. 解决方法是创建一个单独的字段,专门用于支持序列化,该序列化将字典的元素公开为键/值对的列表。 You then also have to mark the dictionary member with the XmlIgnore attribute. 然后,您还必须使用XmlIgnore属性标记字典成员。

Alternatively, you can use something other than XmlSerializer (like DataContractSerializer ) which does support dictionary types. 另外,您可以使用XmlSerializer之外的其他东西(例如DataContractSerializer )来支持字典类型。

Here's a link to an article which provides a good example of how modify your type to support XML Serialization with a dictionary. 这里是文章链接 ,提供了一个很好的示例,说明了如何修改类型以支持带字典的XML序列化。

One important point if you use this code - the serialized items may appear in arbitrary order in the output. 如果使用此代码,则有一点很重要-序列化的项目可能会以任意顺序出现在输出中。 This is a consequence of using dictinoaries (which are unordered) as the storage model for your data. 这是因为使用专断词(无序)作为数据的存储模型的结果。

[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);   
        }   
    }   
}  

I know this has been answered before, but since I have a very concise way (code) for doing IDictionary serialization with the DataContractSerializer class (used by WCF, but could and should be used anywhere) I couldn't resist contributing it here: 我知道以前已经回答过这个问题,但是由于我有一种非常简洁的方式(代码)来使用DataContractSerializer类(由WCF使用,但是可以并且应该在任何地方使用)进行IDictionary序列化,所以我不能拒绝在这里提供它:

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);
        }
    }
}

This works perfectly in .NET 4 and should also work in .NET 3.5, although I didn't test it yet. 尽管我尚未对其进行测试,但它在.NET 4中可以完美运行,并且在.NET 3.5中也可以运行。 I did the streaming to string because it was more convenient to me, although I could have introduced a lower-level serialization to Stream and then used it to serialize to strings, but I tend to generalize only when needed (just like premature optimization is evil, so it is premature generalization...) 我将流式传输到字符串是因为它对我来说更方便,尽管我可以将较低级别的序列化引入Stream,然后用它来序列化为字符串,但是我倾向于只在需要时进行泛化(就像过早的优化是邪恶的一样) ,这是过早的概括...)

Usage is very simple: 用法很简单:

// 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 will be a verbatim copy of myDict. myDictCopy将是myDict的逐字记录副本。

You'll also notice that the generic methods provided will be able to serialize any type (to the best of my knowledge) since it is not limited to IDictionary interfaces, it can be really any generic type T. 您还将注意到,提供的通用方法将能够序列化任何类型(据我所知),因为它不仅限于IDictionary接口,它实际上可以是任何通用类型T。

Hope it helps someone out there! 希望它可以帮助某个人!

I suggest you use the DataContractSerializer. 我建议您使用DataContractSerializer。 It does support dictionaries. 它确实支持字典。

You can't but another way to do this would be to create an simple object which hold Value and Key properties. 但是,另一种方法是创建一个具有Value和Key属性的简单对象。 Then use List(Of thatObject) and it should work. 然后使用List(Of thatObject),它应该可以工作。 But that depend if you only want to transport a value key data cause all others methods which is part of dictionary won't be available. 但这取决于您是否只想传输值键数据,导致字典中一部分的所有其他方法均不可用。

The short answer: You cant 简短的答案: 你不能

This is because even though you can imagine the serialization scheme, .NET Serializer cannot guarantee that the keys re-serialized will have the same hash value. 这是因为即使您可以想象序列化方案,.NET序列化程序也不能保证重新序列化的键将具有相同的哈希值。

Long answer: You can, but it's a lot of work 长答案: 可以,但这需要很多工作

The solution for you is to either do manual serialization of the entire object, or to replace Dictionary with a simple Wrapper Property that wraps IDictionary , but exposes it as a list of pairs. 为您提供的解决方案是对整个对象进行手动序列化,或用一个简单的Wrapper属性(将IDictionary包裹起来,但将其公开为成对列表)替换Dictionary。 (you can convert it later if you need it.) (您可以稍后将其转换。)

However : this leaves the same problem as above, you cannot gaurantee a re-serialized key will have the same hashcode as before it was serialized. 但是 :与上面的问题相同,您不能保证重新序列化的密钥将具有与序列化之前相同的哈希码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM