When I do a sum operation on some objects I have, they don't return the expected result and instead miss the last item in the list.
Here's the models used:
public class Item
{
public decimal Price { get; set; }
public List<ItemOption> Options { get; set; }
}
public class ItemOption
{
public decimal? Price { get; set; }
}
So when I do a sum operation like so it gives incorrect results, missing the last item...
items.Sum(x => x.Price x.Options?.Sum(c => c.Price) ?? 0);
But when I do it with brackets like this, it works...
Console.WriteLine(items.Sum(x => x.Price (x.Options?.Sum(c => c.Price) ?? 0)));
Any idea why adding brackets here would make it work as expected?
Here's something I've tried, first write line returns £16.80 and 2nd write line returns £10.20
var items = new List<Item>
{
new Item
{
Price = 4.20M,
Options = new List<ItemOption>
{
new ItemOption
{
Price = null
}
}
},
new Item
{
Price = 6.00M,
Options = new List<ItemOption>
{
new ItemOption
{
Price = null
}
}
},
new Item
{
Price = 1.30M
},
new Item
{
Price = 5.30M
}
};
Console.WriteLine(items.Sum(x => x.Price (x.Options?.Sum(c =>
c.Price) ?? 0)));
Console.WriteLine(items.Sum(x => x.Price x.Options?.Sum(c =>
c.Price) ?? 0));
CodePudding user response:
This happens due to C# operator precedence, addition has higher precedence then null-coalescing operator, so in the first case if x.Options
is null x.Price x.Options?.Sum(c => c.Price) ?? 0
is evaluated as:
(x.Price (decimal?)null) ?? 0
Which is evaluated as:
null ?? 0
Due to lifted operators rules:
The predefined unary and binary operators or any overloaded operators that are supported by a value type
T
are also supported by the corresponding nullable value typeT?
. These operators, also known as lifted operators, produce null if one or both operands are null; otherwise, the operator uses the contained values of its operands to calculate the result. For example:
int? a = 10;
int? b = null;
int? c = 10;
a ; // a is 11
a = a * c; // a is 110
a = a b; // a is null