2

I have some code which is failing - actually I cannot edit it. Following here and I'm trying to figure out the operation of this code, i.e. what this is doing. Its failing, but I do not know where exactly.

Dictionary<long, IList<Cell>> ByBlock =
                mCache.ListBlocks.SelectMany(e => e.Value).Where(e => listBlocks.Contains(e.Key)).Select(
                Block => new KeyValuePair<long, IList<CellToSubCatchment>>(Block.Key,
                    DataMgr.GetMapping(
                    "CASH",
                    Block,
                    GetKey(IdKeys, Block),
                    mType))).ToDictionary(e => e.Key, e => e.Value);

I'm getting the error: Value cannot be null, but I do not know what value is null and since I cannot edit the code or run Lambda's in the immediate window, I'm having trouble debugging this. So any ideas on how it works or the better way to look at these lambdas?

5
  • 3
    Welcome to the pain of lambdas (I actually like them but handling errors is a pain). I'd suggest splitting it down into several one liners, re-running and working out which statement is causing the problem. Commented Apr 17, 2014 at 11:42
  • @Liath I totally second that - I also like lambda expressions, but unfortunately no new lambda expressions can be formulated while debugging! Commented Apr 17, 2014 at 11:43
  • 1
    @Codor good point. To clarify I mean var a = mCache.ListBlocks.SelectMany(); var b = a.Where(); var c = b.Select() and so on... it's horrible but you'll need to modify your code to find the culprit Commented Apr 17, 2014 at 11:44
  • 1
    I believe that at some point, the generated Value would be null, such that the conversion to a dictionary fails; perhaps the SelectMany fails. Commented Apr 17, 2014 at 11:45
  • you can watch bpth mCache and listblocks in the watch window is neither is null then e is (an item in the collection) Commented Apr 17, 2014 at 20:52

3 Answers 3

3

It's a bit misleading since dictionaries have keys and values, but you'll get that error when trying to insert a null key into a Dictionary (you're allowed to have null values in a dictionary).

I think you can filter out null values earlier on in your query so you don't end up with a null key later on. I added a condition for && e.Key != null.

Dictionary<long, IList<Cell>> ByBlock =
    mCache.ListBlocks.SelectMany(e => e.Value)
          .Where(e => listBlocks.Contains(e.Key)
                      && e.Key != null)  // filter out `null` values
          .Select(Block =>
                    new KeyValuePair<long, IList<CellToSubCatchment>>(
                        Block.Key,
                        DataMgr.GetMapping("CASH", Block,
                                           GetKey(IdKeys, Block),
                                           mType)))
          .ToDictionary(e => e.Key, e => e.Value);
Sign up to request clarification or add additional context in comments.

Comments

2

Reformating the code a bit it looks like this:

Dictionary<long, IList<Cell>> ByBlock = 
       mCache.ListBlocks
         .SelectMany(e => e.Value)
         .Where(e => listBlocks.Contains(e.Key))
         .Select(Block => new KeyValuePair<long, IList<CellToSubCatchment>>(
                Block.Key,
                DataMgr.GetMapping("CASH",Block,GetKey(IdKeys, Block), mType))
         )
         .ToDictionary(e => e.Key, e => e.Value);

My best bet would be that the ListBlocks.SelectMany(e => e.Value) call fails, because in the ListBlocks collection there is a element that has a Value collection equal to null.

This is a quirk of SelectMany, and I usually go around it using something like

mCache.ListBlocks.SelectMany(e => e.Value ?? List<MyType>())

EDIT:
On closer view, that case just throws a NullReferenceException, the ArgumentNullException you are recieving is more likely to come from the ToDictionary call.

Also, you could remove the second Select call, as well as the painful-to-look-at KeyValuePair constructior, by just using the ToDictionary method to do the evaluation:

Dictionary<long, IList<Cell>> ByBlock = 
       mCache.ListBlocks
         .SelectMany(e => e.Value)
         .Where(e => listBlocks.Contains(e.Key))
         .ToDictionary(
              block => block.Key, 
              block => DataMgr.GetMapping("CASH",block,GetKey(IdKeys, block), mType))
         );

Comments

0

Here's what I like to do with messy LINQ. It makes it much easier to read and debug.

var allListBlockValues = mCache.ListBlocks.SelectMany(listBlock => listBlock.Value);

var matchingListBlockValues = allListBlockValues.Where(e => listBlocks.Contains(e.Key))


Dictionary<long, IList<Cell>> ByBlock = new Dictionary<long, IList<Cell>>();

foreach (var Block in matchingListBlockValues)
{
     long key = Block.Key;
     var value = DataMgr.GetMapping("CASH",Block,GetKey(IdKeys, Block), mType);

     ByBlock.Add(key, value);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.