-1

I want to use the FindAll method in C# in like this:

List<Card> cards = new List<Card>();
cards.AddRange(testCaseCards);
Console.WriteLine(cards.Count);
List<List<Card>> cardsSuits = new List<List<Card>>();
List<Card> tempList = new List<Card>();
for (int i = 0; i < 4; ++i)
{
    Console.WriteLine(cards[i].Suit);
    tempList = cards.FindAll(card => card.Suit == (Suit)i);
    cardsSuits.Add(tempList);
}

When I initialize my code with testCaseCards containing 9 cards, everything works just fine up until the FindAll query. The value of cards.Count is 9 and cards[i].Suit returns the respective suits.

But when FindAll executes it throws an exception that "card was null" and I'm looking for a way to step into the FindAll as it goes through the cards and set a breakpoint to examine values and determine the exact cause of failure. I looked at this answer which mentions Linq in passing but doesn't provide any real guidance about debugging a null exception while the Linq query is running.

Also, if you notice any other problems in my code please point them out.

IVSoftware
  • 5,732
  • 2
  • 12
  • 23
TimBrem
  • 31
  • 1
  • 4
  • 3
    How is `Suit` defined? What is `testCaseCards`? Can you show a more [complete example of your code](https://stackoverflow.com/help/minimal-reproducible-example)? – wkl Jun 22 '22 at 16:57
  • Sorry for not giving more information. Suit is an enumeration of traditional card suits (Clubs, Diamonds etc.) and testCaseCards is just an array of Cards (a class containing the Suits enumeration). I thought that this was not so important as the only think not working is the exception telling me that card is null which I don't understand because the line of code above (Console.WriteLine(cards[i].Suit);) works just fine. – TimBrem Jun 22 '22 at 17:16
  • 3
    You're getting this error because `testCaseCards` contains a null value. There's no way for us to know why it contains a null value without seeing the code that initializes/populates it. – Andrio Jun 22 '22 at 17:24
  • 1
    To confirm 'testCaseCards' contains null value you could try `tempList = cards.FindAll(card => card?.Suit == (Suit)i) ` which should not throw any errors – coder_b Jun 22 '22 at 17:29
  • Thank you so much, it works with the card? I also found why there was a null value in the first place. Thank you again! – TimBrem Jun 22 '22 at 20:24

1 Answers1

1

One way to debug the FindAll (or any Linq) is by creating a Predicate method. For example:

private static bool isSuit(Card card, Suit suit)
{
    if (card == null)
    {
        // Set a break point here. When the null card comes in
        // (as it surely will) you can answer 'why' for yourself.
        System.Diagnostics.Debug.Assert(false, "Expecting a non-null card");
        return false; // But at least it won't crash now.
    }
    else
    {
        return card.Suit == suit;
    }
}

Now you will be able to step into this method by changing your FindAll statement to call the predicate instead:

tempList = cards.FindAll(card => isSuit(card, suit));

In addition there is another potential problem. You have a loop where i could mean anything.

for (int i = 0; i < 4; ++i)

In fact the first two statements in the loop interpret it in very different ways. The first statement in the loop seems to think that i is the index in the cards collection. You say cards holds 9 cards. Why stop the loop after 4 then?

Console.WriteLine(cards[i].Suit);

On the other hand, the second line tries to cast i to Suit (which has only four values). if i does go past 4, this won't be good. I would strongly encourage you to change your loop to something like this where we know for sure which collection is being iterated:

foreach (Suit suit in Enum.GetValues(typeof(Suit)))
{
    Console.Write(suit.ToString());
    tempList = cards.FindAll(card => isSuit(card, suit));
    cardsSuits.Add(tempList);
    Console.WriteLine($" has {tempList.Count} cards.");
}

The test case I ran gets this:

9
Clubs has 1 cards.
Diamonds has 2 cards.
Hearts has 3 cards.
Spades has 3 cards.

IVSoftware
  • 5,732
  • 2
  • 12
  • 23
  • 1
    Thank you so much for your detailed explanation! The Console.WriteLine(cards[i].Suit); was only a crude attempt at debugging but the tip with Enum.GetValues is very nice indeed! :) – TimBrem Jun 22 '22 at 20:26
  • Glad to assist! I submitted a new edit because your post raises a distinct and useful question about how to nail down root cause of a null (or any other) exception that's thrown _while_ a `Linq` query is executing and my hope is to see it reopened. IMO it's an oversimplification to say this is a duplicate of [What is a NullReferenceException, and how do I fix it?](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it). – IVSoftware Jun 24 '22 at 00:40