disruptive
disruptive

Reputation: 5946

Lambda function c# meaning

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?

Upvotes: 2

Views: 153

Answers (3)

zmarks22
zmarks22

Reputation: 318

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

Upvotes: 0

SWeko
SWeko

Reputation: 30892

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

Upvotes: 2

Grant Winney
Grant Winney

Reputation: 66449

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

Upvotes: 3

Related Questions