如何调试XML反序列化?

3

我想知道你有没有任何关于如何调试以下XML反序列化的技巧?我无法让它工作。反序列化器基本上创建了召唤和斜杠实例,但它们所有的属性都是空的。相关的类如下所示。


带有反序列化器的SkillCollection类:

[DataContract(Name = "Skills", Namespace = "")]
public class SkillCollection
{

[DataMember(Name = "Slash")]
public Skill Slash { get; set; }

[DataMember(Name = "Summon")]
public Skill Summon { get; set; }

public static object Deser(string path, Type toType)
{
    var s = new DataContractSerializer(toType);
    using (FileStream fs = File.Open(path, FileMode.Open))
    {
        object s2 = s.ReadObject(fs);
        if (s2 == null)
            Console.WriteLine(@"  Deserialized object is null");
        else
            Console.WriteLine(@"  Deserialized type: {0}", s2.GetType());
        return s2;
    }
}

它通过属性Skills从另一个类中调用:
Skills = (SkillCollection)SkillCollection.Deser(
            Path.Combine(path, "Skills.xml"), 
            typeof(SkillCollection));

技能类别:

public class Skill
{
    //Cast: time it takes to cast it
    [DataMember(Name = "Cast")]
    public float Cast { get; set; }

    //ReCast: cooldown period before player can cast it again
    [DataMember(Name = "ReCast")]
    public float ReCast { get; set; }

    [DataMember(Name = "MPCost")]
    public int MpCost { get; set; }

    public Timer Timer { get; private set; }
    public bool Ready { get; set; }

    public Skill()
    {
        Ready = true;

        Timer = new Timer { Interval = ReCast + 500, AutoReset = false };
        Timer.Elapsed += OnTimedEvent;
    }

    //Runs when recast is up
    private void OnTimedEvent(object source, ElapsedEventArgs e)
    {
        Ready = true;
    }
}

XML文件:


<Skills>
  <Slash>
    <Cast>0.00</Cast>
    <ReCast>60.00</ReCast>
    <MPCost>0</MPCost>
  </Slash>
  <Summon>
    <Cast>5.98</Cast>
    <ReCast>2.49</ReCast>
    <MPCost>0</MPCost>
  </Summon>
</Skills>

为避免混淆,我的目标是运行反序列化器,然后使SkillCollection类包含两个Skill实例(Slash和Summon),并能够通过它们的属性分别访问它们。

感谢您在调试方面提供的任何帮助/提示。


1
附加问题:1)属性的顺序是否必须与XML中的顺序匹配?2)如果XML中并不是所有块都有属性(比如XML中有第三个技能叫做踢,但在SkillCollection中没有踢的属性),会出现问题吗?3)反过来呢(有属性没有块与之匹配),会有问题吗?谢谢。 - Anders
1
我认为调试的第一步是通过序列化器运行您的对象并查看它生成的XML。然后,您可以将其与提供的XML进行比较。但是,DataContractSerializer不是我的首选。它有很多陷阱,例如它要求属性在xml中按字母顺序排列。请改用XmlSerializer - Mike Zboray
1
@mikez 感谢!按字母顺序排序并使用 Magnus 提供的代码解决了问题。感谢你们两个! - Anders
1
@mikez 我使用DataContractSerializer的原因是我可以将我的属性设置器设为私有。我发现这篇文章很有帮助:http://web.archive.org/web/20130430190551/http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/ - Anders
1个回答

1

Anders,

最近我做了一个类似的任务。看着你的代码,似乎你设置了错误的DataContract名称和命名空间。在Skill类和SkillCollection类上方都需要指定:[DataContract(Name = "Skills", Namespace = "")]。这对于序列化程序“允许”进入属性非常重要。请记住,仅在SkillCollection类上方设置它是不够的。

编辑:我最初认为您可以省略Namespace,但实际上不行。它必须设置为Namespace="",如果您在XML中未指定命名空间,则为此情况,或者设置为您指定的命名空间,如果您指定了命名空间,则为此情况。

另外,调试的一种方法是将Deser方法更改为:

    public static object Deserialize(string path, Type toType)
    {
        using (var sr = new FileStream(path, FileMode.Open))
        {
            SkillCollection p = null;
            XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(sr, new XmlDictionaryReaderQuotas());
            var serializer = new DataContractSerializer(toType);

            while (reader.Read())
            {
                switch (reader.NodeType)
                {
                    case XmlNodeType.Element:
                        if (serializer.IsStartObject(reader))
                        {
                            Console.WriteLine(@"Found the element");
                            p = (SkillCollection)serializer.ReadObject(reader);
                            Console.WriteLine("{0} {1}    id:{2}",
                                p.Slash.ToString(), p.Summon.ToString());
                        }
                        Console.WriteLine(reader.Name);
                        break;
                }
            }

            return p;
        }
    }

1
感谢您的编辑。我尝试按照最初的建议省略了命名空间,但是根据您提供的调试代码,明显需要将其包含进来。 - Anders

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接