4

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

}
  • possible duplicate of [call one constructor from another](http://stackoverflow.com/questions/4009013/call-one-constructor-from-another) – verdesmarald Sep 28 '12 at 03:19

3 Answers3

3

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.

lc.
  • 113,939
  • 20
  • 158
  • 187
2

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");
Felix
  • 830
  • 10
  • 17
1

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
}
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • @lc.: Yes... You could refactor out that check into a method, or you could send a magic number to the other constructor that means that it should determine the size from the type. – Guffa Sep 28 '12 at 07:36