使用自定义IXmlSerializable实现的C#中的XML反序列化

时间:2018-10-29 01:32:16

标签: c# .net-core discord

我正在使用C#制作Discord机器人,并已准备好所有逻辑,但是,当我尝试从保存配置和其他内容的文件中读取XML时,遇到了问题。

我不想依靠SQLite进行存储。

每当我尝试反序列化时,它都会抛出一个System.InvalidOperationException和一个System.NullReferenceException

IXmlSerializable的自定义实现的示例

namespace RoleBot
{
    public class RoleWatch
    {
        public DiscordGuild Guild { get; set; }

        public DiscordChannel Channel { get; set;  }

        public DiscordMessage Message { get; set; }

        public DiscordEmoji Emoji { get; set; }

        public DiscordRole Role { get; set; }

        public RoleWatch() { }

        // Constructor
        public RoleWatch(DiscordGuild guild, DiscordChannel channel, string message, DiscordEmoji emoji, DiscordRole role)
        {
            Guild = guild;
            Channel = channel;
            Message = Channel.GetMessageAsync(UInt64.Parse(message)).Result;
            Emoji = emoji;
            Role = role;
        }

        public RoleWatch(string guild, string channel, string message, string emoji, string role)
        {
            Guild = Bot.Client.GetGuildAsync(UInt64.Parse(guild)).Result;
            Channel = Guild.GetChannel(UInt64.Parse(channel));
            Message = Channel.GetMessageAsync(UInt64.Parse(message)).Result;
            Emoji = DiscordEmoji.FromName(Bot.Client, emoji);
            Role = Guild.GetRole(UInt64.Parse(role));
        }

        /*
         * Custom implementation of the Read method in IXmlSerializable to cater to a descriptive yet consise
         * XML config file
         */
        public void ReadXml(XmlReader reader)
        {
            reader.ReadStartElement();
            var guild = reader.ReadElementString("Guild");
            var channel = reader.ReadElementString("Channel");
            var message = reader.ReadElementString("Message");
            var emoji = reader.ReadElementString("Emoji");
            var role = reader.ReadElementString("RoleID");
            reader.ReadEndElement();

            Guild = Bot.Client.GetGuildAsync(UInt64.Parse(guild)).Result;
            Channel = Guild.GetChannel(UInt64.Parse(channel));
            Message = Channel.GetMessageAsync(UInt64.Parse(message)).Result;
            Emoji = DiscordEmoji.FromName(Bot.Client, emoji);
            Role = Guild.GetRole(UInt64.Parse(role));
        }

        /*
         * Custom implementation of WriteXml method in IXmlSerializable to cater to a descriptive XML file so clients
         * can configure without needing to refer to documentation.
         */
        public void WriteXml(XmlWriter writer)
        {
            writer.WriteComment("Guild: " + Guild.Name);
            writer.WriteComment("Channel: " + Channel);
            writer.WriteComment("Message: " + Message);
            writer.WriteComment("Emoji: " + Emoji);
            writer.WriteComment("Role: " + Role.Name);
            writer.WriteElementString("Guild", Guild.Id.ToString());
            writer.WriteElementString("Channel", Channel.Id.ToString());
            writer.WriteElementString("Message", Message.Id.ToString());
            writer.WriteElementString("Emoji", Emoji.GetDiscordName());
            writer.WriteElementString("RoleID", Role.Id.ToString());
        }
    }
}

这是要反序列化和序列化的XML文件

<?xml version="1.0" encoding="utf-8"?>
<Config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <AutoRemoveFlag>false</AutoRemoveFlag>
  <Prefix>r!</Prefix>
  <Role>
    <!--Guild: The Failures-->
    <!--Channel: Channel #test (485962904466751494)-->
    <!--Message: Message 496344956252717056; Attachment count: 0; Embed count: 0; Contents: Add Reaction Here-->
    <!--Emoji: <:nut:473756909610991626>-->
    <!--Role: nut-->
    <Guild>397456625813815297</Guild>
    <Channel>485962904466751494</Channel>
    <Message>496344956252717056</Message>
    <Emoji>:nut:</Emoji>
    <RoleID>505000750632534017</RoleID>
  </Role>
  <Role>
    <!--Guild: The Failures-->
    <!--Channel: Channel #test (485962904466751494)-->
    <!--Message: Message 496344956252717056; Attachment count: 0; Embed count: 0; Contents: Add Reaction Here-->
    <!--Emoji: <:confusedCopy:473756234735026176>-->
    <!--Role: memes-->
    <Guild>397456625813815297</Guild>
    <Channel>485962904466751494</Channel>
    <Message>496344956252717056</Message>
    <Emoji>:confusedCopy:</Emoji>
    <RoleID>505000818647367680</RoleID>
  </Role>
</Config>

每个RoleWatch对象都存储在以下类的List

namespace RoleBot
{
    [XmlInclude(typeof(List<RoleWatch>))]
    public class Config
    {
        public string Token { get; set; }

        public bool AutoRemoveFlag { get; set; }

        [XmlElement("Prefix")]
        public string CommandPrefix { get; set; }

        [XmlElement("Role")]
        public List<RoleWatch> RolesToWatch { get; set; }

        public Config () { RolesToWatch = new List<RoleWatch>(); }
    }
}

这些是调用序列化器和反序列化器的方法:

/* Refresh Config Method
        *
        * Used to load the configuration into the assembly
        * Gets each <Role> Node from config.xml and deserializes them into RoleWatch Objects
        */
        internal static Task RefreshConfig ()
        {
            using (var reader = new StreamReader(ConfigPath))
            {
                var serializer = new XmlSerializer(typeof(Config));

                Config = serializer.Deserialize(reader) as Config;
            }

            return Task.CompletedTask;
        }

        /*
         * Updates the config file for permanent storage of settings and roles to watch
         */
        internal static Task UpdateConfigFile()
        {
            using (var writer = XmlWriter.Create("config.xml", new XmlWriterSettings {Indent = true}))
            {
                /*
                 * Initializes a new XmlSerializer with type config and RoleWatch
                 */
                var serializer = new XmlSerializer(typeof(Config));

                serializer.Serialize(writer, Config);
            }

            return Task.CompletedTask;
        }

我尝试了在堆栈溢出中发现的所有可能方法,但似乎没有任何效果! 任何帮助将不胜感激! 谢谢。

0 个答案:

没有答案