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 :)
source to share
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
.
source to share
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.
source to share