Why is this Linq not working

I have a rather ugly object (yes, I need a Tuple there :)):

var roomToIndex = new Dictionary<RoomNode, Tuple<Int32, Dictionary<GrowDirections, Int32>>>();

      

I initialize this dictionary like this:

for (var i = 0; i < roomsAdjacent.Count(); i++) {
    roomToIndex.Add(roomsAdjacent.ElementAt(i), new Tuple<Int32, Dictionary<GrowDirections, Int32>>(i, new Dictionary<GrowDirections, Int32>()));
    roomToIndex.ElementAt(i).Value.Item2.Add(GrowDirections.Top, 0);
    roomToIndex.ElementAt(i).Value.Item2.Add(GrowDirections.Right, 0);
    roomToIndex.ElementAt(i).Value.Item2.Add(GrowDirections.Bottom, 0);
    roomToIndex.ElementAt(i).Value.Item2.Add(GrowDirections.Left, 0);
}

      

Where roomsAdjacent is a list of RoomNodes and GrowDirections [Flags list].
After these initialization steps, I increment the Integer values โ€‹โ€‹of the "internal" dictionaries and finally I want to get the GrowDirection and RoomNode with the highest value.
I am trying to do it like this (for now):

///Use the Counts to determine optimal FillDirection
var rDC = roomToIndex
    ///Select the RoomNode and the GrowDirection (incl. Count) with the highest Count for each Room
    .Select(r => new { RoomNode = r.Key, Dict = r.Value.Item2.OrderByDescending(dirCount => dirCount.Value).ToList()[0] })
    ///Order those RoomNodes and GrowDirections descending
    ///Take the first Element and used the Dict Key (GrowthDirection)
    .OrderByDescending(rGI => rGI.Dict.Value).ToList();
var rDC0 = rDC[0];
if (rDC0.Dict.Key == GrowDirections.Top || rDC0.Dict.Key == GrowDirections.Bottom)
    fillDirection = GrowDirections.Top | GrowDirections.Bottom;
else
    fillDirection = GrowDirections.Right | GrowDirections.Left;
foreach (var rTI in roomToIndex.Where(rTI => rTI.Key != rDC0.RoomNode))
    roomCellCount[rTI.Value.Item1] = 0;

      

RDC has type {RoomNode, Dictionary} and I have no problem. But when I debug and go to the next line:

var rDC0 = rDC[0];

      

The debugger skips the line, goes straight to the "if" statement, and throws an error telling me that I got a NullReferenceEx !! When I look at the values โ€‹โ€‹in my "rDC object" there is no null value.

What could it be? Thanks for the hint / help :)

+3


source to share


2 answers


Looking at your code, the type rDC

is List<KeyValuePair<RoomNode, something very complicated>

. It is not something very complex that KeyValuePair<TKey, TValue>

matters , but the value type ( struct

). This means it List<KeyValuePair<TKey, TValue>>

cannot contain items null

. This means it rDC0

cannot be null

. This is basically also what you tell us.

But then, if you get NullReferenceException

as you described, it should be rDC0.Dict

that null

. However, the property Dict

cannot be null

because it was explicitly initialized with Dictionary<GrowDirections, Int32>

your new initialization code.

Thus, the code you provided in the question should not show the behavior that you described. Either your code is slightly different, or the behavior you get is not exactly what you describe. The problem you mentioned could be the result of debugging a release version or symbols that are out of sync with the executable code.

I suggest you solve one or more of the following things in order to fix your problem:

  • Rebuild the solution to make sure the debugger shows the correct source code when debugging
  • Switch to debug build to disable optimizations that will obfuscate debugging
  • Divide your data and code into smaller pieces to get rid of complex and difficult to understand code.


The last suggestion is what will solve (or solve) your problem. Let me give you some pointers:

Instead of using, Dictionary<GrowDiretions, Int32>

you could create a type with four properties, which will hopefully make it clearer what your code is doing:

class GrowCounts {
  public Int32 TopCount { get; set; }
  public Int32 RightCount { get; set; }
  public Int32 BottomCount { get; set; }
  public Int32 LeftCount { get; set; }
  public GrowDirections MaxGrowDirection {
    get { // Return GrowDirections.Top if TopCount has the highest count etc. }
  }
}

      

Instead of using new Tuple<T1, T2>

use Tuple.Create

the compiler deduced types of tuples.

Do you really need Tuple

where the first element is the index? Some of your code for loops with Count

and ElementAt

and for accessing collections in this way requires an index. However, perhaps you can convert these loops to loops foreach

and in the process you find that the index is not needed. If possible, you can get rid of Tuple

.

+1


source


Apparently (as per what you wrote) this is due to a tricky Linq statement that has a side effect that somehow leads to a null reference error that puts it in its own function. You may be able to find out more about what exactly caused this by seeing what happens if you put a simpler Linq Select statement before initialization. For more information on how you can track down what's really going on here, see Martin.



0


source







All Articles