简体   繁体   中英

C#; NullReferenceException was unhandled; value being reset to 0

When I attempt to call my ToString() Method in the Deck class, it gives me a "NullReferenceException was unhandled" error. Doing some testing, I have figured out that when it is attempting to call the Deck.ToString() method, the size was set to 0. It's supposed to be set when the constructor is called, and I don't know what is resetting it.

Main Method:

public class DeckTest
{

    public static void Main()
    {
        Deck toTest = null;
        Console.WriteLine("What type of Deck would you like to create?");
        toTest = new Deck(Console.ReadLine());

        Console.WriteLine(toTest);

    }

}

The Deck Class:

class Deck
{
    String type;
    int size;
    String deckList;
    Card[] deck;

    public Deck(String type, int size)
    {
        deck = new Card[size];
        this.type = type;
        this.size = size;

       while (deck[size - 1] == null)
       {

           Card newCard;
           Console.WriteLine("Please Enter the Type, Name, Colour (if card has no Colour, enter 'Colourless'), Colour Identity, Text, Mana Cost (if applicable), Converted Mana Cost (if applicable), Power (if applicable), Toughness (if applicable), separated by semicolons.");
           String line = Console.ReadLine();
           string[] card = line.Split(';');
           if (card[0].Equals("Land", StringComparison.OrdinalIgnoreCase))
           {
               newCard = new Card(card[0], card[1], card[3], card[4]);
           }
           else if (card[0].Equals("creature", StringComparison.OrdinalIgnoreCase))
           {
               newCard = new Card(card[0], card[1], card[2], card[3], card[4], card[5], int.Parse(card[6]), int.Parse(card[7]), int.Parse(card[8]));
           }
           else
           {
               newCard = new Card(card[0], card[1], card[2], card[3], card[4], card[5], int.Parse(card[5]));
           }
           addCard(newCard);
           }
   }


    public Deck(String type)
    {
        if (type.Equals("Standard", StringComparison.OrdinalIgnoreCase))
        {
            new Deck(type, 60);
        }
        else if (type.Equals("Extended", StringComparison.OrdinalIgnoreCase))
        {
            new Deck(type, 60);
        }
        else if (type.Equals("Modern", StringComparison.OrdinalIgnoreCase))
        {
            new Deck(type, 60);
        }
        else if (type.Equals("Commander", StringComparison.OrdinalIgnoreCase)|| type.Equals("EDH", StringComparison.OrdinalIgnoreCase))
        {
            new Deck(type, 100);
        }
    }

    void addCard (Card newCard)
    {
        int count = 0;

        while (deck[count] != null && count < size)
        {
            count++;
        }

        if (count < size)
        {
            deck[count] = newCard;
        }
        else
        {
            Console.WriteLine("This deck is full.");
        }
    }

    public override string ToString()
    {
        String output = "";
        int count = 0;

        while (deck[count] != null && count < size-1)
        {
            output += deck[count] + "/n";
        }

        return output;
    }

}

The new keyword is creating an entirely new instance (that is promptly discarded), not modifying the existing instance from your constructor.

You should use the factory pattern (a static method which instantiates a different object depending on its parameters then returns it) instead:

public static Deck FromType(String type)
{
    if (type.Equals("Standard", StringComparison.OrdinalIgnoreCase))
    {
        return new Deck(type, 60);
    }
    else if (type.Equals("Extended", StringComparison.OrdinalIgnoreCase))
    {
        return new Deck(type, 60);
    }
    else if (type.Equals("Modern", StringComparison.OrdinalIgnoreCase))
    {
        return new Deck(type, 60);
    }
    else if (type.Equals("Commander", StringComparison.OrdinalIgnoreCase)|| type.Equals("EDH", StringComparison.OrdinalIgnoreCase))
    {
        return new Deck(type, 100);
    }

    throw new ArgumentOutOfRangeException("Bad type");
}

You can then instantiate your new Deck with toTest = Deck.FromType(Console.ReadLine()) instead of using the new keyword.

I'd say it's not the best way to get the object, you may try to something like:

public class Deck
{
    public static Deck GetDeck(String type)
    {
        if (type.Equals("Standard", StringComparison.OrdinalIgnoreCase))
        {
            return new Deck(type, 60);
        }
        else if (type.Equals("Extended", StringComparison.OrdinalIgnoreCase))
        {
            return new Deck(type, 100);
        }
    }
}

And than get Deck like this:

Deck.GetDeck("foo");

To call another constructor, you do that before the body of the method, not inside it:

public Deck(String type) : this(type,
  type.Equals("Standard", StringComparison.OrdinalIgnoreCase) ||
  type.Equals("Extended", StringComparison.OrdinalIgnoreCase) ||
  type.Equals("Modern", StringComparison.OrdinalIgnoreCase)
? 60 : 100)
{
  // nothing more here
}

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