简体   繁体   中英

NullReferenceException on this C# code

Here is the entire code for my class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Xml.Linq;

namespace SharpDIC.Entities
{
    /// <summary>
    /// Represents a forum on the Dream.In.Code website.
    /// </summary>
    public class Forum
    {
        //Forum information is given by this XML call:
        //http://www.dreamincode.net/forums/xml.php?showforum=NUMBER_GOES_HERE

        public string Name { get; set; }
        public string ID { get; set; }
        public string URL { get; set; }
        public List<Subforum> Subforums { get; set; }

        /// <summary>
        /// Load a forum by providing an ID.
        /// </summary>
        /// <param name="id">A forum's individual ID number.</param>
        public Forum(string ID)
        {
            WebClient webClient = new WebClient();
            string htmlSource = webClient.DownloadString(new Uri(String.Format("http://www.dreamincode.net/forums/xml.php?showforum={0}", ID)));
            XDocument xml = XDocument.Parse(htmlSource);

            var forumXML = xml.Element("ipb").Element("forum");

            //Load general profile information.
            this.Name = forumXML.Element("name").Value;
            this.ID = forumXML.Element("id").Value;
            this.URL= forumXML.Element("url").Value;

            //Load subforums.
            var subforumsXML = xml.Element("ipb").Element("forum").Element("subforums");
            this.Subforums = (from forum in subforumsXML.Descendants("forum")
                              select new Subforum()
                              {
                                  ID = forum.Element("id").Value,
                                  Name = forum.Element("name").Value,
                                  URL = forum.Element("url").Value,
                                  Description = forum.Element("description").Value,
                                  Type = forum.Element("type").Value,
                                  TopicCount = forum.Element("topics").Value,
                                  ReplyCount = forum.Element("replies").Value,
                                  LastPost = new LastPost()
                                  {
                                      Date = forum.Element("lastpost").Element("date").Value,
                                      Name = forum.Element("lastpost").Element("name").Value,
                                      ID = forum.Element("lastpost").Element("id").Value,
                                      URL = forum.Element("lastpost").Element("url").Value,
                                      UserWhoPosted = new Friend()
                                      {
                                          ID = forum.Element("lastpost").Element("user").Element("id").Value,
                                          Name = forum.Element("lastpost").Element("user").Element("name").Value,
                                          Url = forum.Element("lastpost").Element("user").Element("url").Value,
                                          Photo = forum.Element("lastpost").Element("user").Element("photo").Value,
                                      }
                                  }
                              }).ToList();
        }
    }
}

Basically what it does is parse the information from the returned xml of this address:

http://www.dreamincode.net/forums/xml.php?showforum=1

Here's how I'm running this code:

SharpDIC.Entities.Forum forum = new SharpDIC.Entities.Forum("1");
Console.WriteLine(forum.Name);
Console.WriteLine(forum.URL);
Console.WriteLine(forum.ID);
Console.WriteLine(forum.Subforums[0].LastPost.UserWhoPosted.Name);

Console.ReadLine();

I'm getting an exception on the entire load subforums block; any suggestions?

NullReferenceException was not handled. Object reference not set to an instance of an object.

It's almost certainly that one of the elements you're expecting is missing.

If you run it in the debugger you may find that when it throws the exception, it indicates which actual operation it's on, which would make it much easier.

Alternatively, break out the parsing of individual components into separate methods:

this.Subforums = subforumsXML.Descendants("forum")
                             .Select(ParseForum)
                             .ToList();

...

static SubForum ParseForum(XElement forum)
{
    return new Subforum
    {
        ID = forum.Element("id").Value,
        ...
        LastPost = ParseLastPost(forum.Element("lastpost"))
    };
}

static LastPost ParseLastPost(XElement lastPost)
{
    ...
}

I've found this can keep the query expressions more manageable.

One way of avoiding NREs when there's a missing element that you're just trying to get the value of is to use a conversion instead of the Value property, eg

ID = (string) forum.Element("id")

That will set ID to null if the id element is missing. Obviously if it's actually a required property, throwing the exception is better, but for optional properties it's really useful.

you should probably check to make sure that subforumsXML != null before using your linq on it.

you could break this operation into a couple of lines....

    var subforumsXML = xml.Element("ipb").Element("forum").Element("subforums");

// goes to

if ( forumXML != null )    // breakpoint here
{
   // ml.Element("ipb").Element("forum") == forumXML
   var subforumsXML = forumXML.Element("subforums");
   if ( subforumsXML != null )
   {
   // do stuff here
   }
}

You never check whether an element exists. For example for the UserWhoPosted every item must have a <lastpost> element, which must have a <user> element, which must have <id> , <name> , <url> and <photo> elements. If any of those are missing, that Element("whatever") will return null so a .Value will fail.

在您的链接中,第一个用户没有照片,可能就是这样

To find the problem, try this extension and then call GetElement rather than Element...

public static System.Xml.Linq.XElement GetElement(this System.Xml.Linq.XContainer doc, string name)
    {
        var element = doc.Element(name);
        if (element == null)
            throw new ApplicationException("Missing element: " + name);
        return element;
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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