2
votes

I would like to create a Dictionary from a list, so I would use this way:

Dictionary<long, List<MyType>> miDicIdMyType = myList.GroupBy(x => x.ForeignKey)
                                              .ToDictionary(x => x.Key, x => x.ToList());

The problem is that sometimes the property can be null, so I can create the dictionary because a dictionary doesn't allow null values as key.

But in this particular case, I have to check if this property is null, and if it is null, throw an exception, because this is an error. In this particular method, I expect that all the items in the list have no null in this property.

So I would can do this:

Dictionary<long, List<MyType>> miDicIdMyType = myList.GroupBy(x => (long)x.ForeignKey)
                                        .ToDictionary(x => x.Key, x => x.ToList());

It is a cast to long, but if it is null, I will get an error. So basically I wanted to do this:

Dictionary<long, MyType> myDic = new Dictionary<long, myType>();
foreach (Mytype iterator in miList)
{
    if (iterator.ForeignKey == null)
    {
        throw new ArgumentNullException("Some items in the collection has null value and it is not expected.");
    }

    if (myDic.ContainsKey(iterator.ForeignKey) == false)
    {
        myDic.Add(iterator.ForeignKey, new List<MyType>());
    }

    myDic[iterator.ForeignKey].Add(iterator);
}

I would like to know if this is a good code or I could do it in a better way, with LINQ or a lambda expression or any other way. I mean, simplify my code.

2
you can refactor x => x.ForeignKey to a multiline lambda expession Func<T, long> and throw an exception in case T.ForeignKey is NULL. - Zein Makki
Another options is to just Dictionary<long?, List<MyType>>. - Erik Philips

2 Answers

3
votes

You are looking for something like that?

Dictionary<long, List<MyType>> miDicIdMyType = myList.GroupBy(x =>
{
    if (x.ForeignKey == null)
        throw new Exception();
    return x.ForeignKey.Value;
})
.ToDictionary(x => x.Key, x => x.ToList());
2
votes

First, you're creating a lookup. Just do this:

var lookup = data.ToLookup(x => x.ForeignKey);

If you need an additional check on the key, a named method does wonders for reusability and readability.

T IsNotNull<T>(T? obj, [CallerMemberName] string name = default(string)) where T : struct
{
    if (obj == null)
        throw new ArgumentNullException(name);
    return obj.Value;
}

var lookup = data.ToLookup(x => IsNotNull(x.ForeignKey));

But I would caution you from even using this at all. Your linq queries should not be relying on/causing side effects, especially with the lazy evaluation. You should be preventing the exceptional cases at all costs, not looking for reasons to raise them. And in this particular case, an exception at this point in code would be inappropriate. It's a simple data issue that should be filtered out.

Why wouldn't you just filter those out in the first place?

var lookup = data.Where(x => x.ForeignKey != null).ToLookup(x => x.ForeignKey.Value);