LINQ operátor Sum (přesněji jeho varianty pro LINQ to objects, v LINQ to Entities je to jinak) je navržen tak, že:
- Výsledkem operace Sum pro prázdnou sekvenci je hodnota nula.
- Pro nullable datový typ (například int?) jsou hodnoty null ve vstupní sekvenci ignorovány.
Platnost i důsledky výše uvedených bodů si můžeme demonstrovat například následujícím příkladem:
static void Main()
{
PrintSum(new List<int?> { });
PrintSum(new List<int?> { null });
PrintSum(new List<int?> { null, 0, null });
PrintSum(new List<int?> { 1, 2, 3, null, 5, 6 });
}
private static void PrintSum(IEnumerable<int?> source)
{
int? sum = source.Sum();
Console.WriteLine(sum == null ? "[null]" : sum.ToString());
}
0
0
0
17
Je zde vidět jedna zajímavost a sice to, že přestože má metoda Sum(this IEnumerable<int?>) návratovou hodnotu deklarovanou typu int? hodnotu null nikdy nevrací.
Tento fakt lze nakonec potvrdit i přímo z implementace metody Sum samotné:
public static int? Sum(this IEnumerable<int?> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
int num = 0;
foreach (int? nullable in source)
{
if (nullable != null)
{
num += nullable.Value;
}
}
return new int?(num); //<--Vrací se vždy int
}
Co když by se nám ale hodilo, aby byl ve výše uvedeném příkladu výsledek místo nuly v prvních dvou případech null (prázdná sekvence a sekvence obsahující pouze hodnoty null)?
Jedno z možných řešení by v takovém případě mohlo být popsat si tuto logiku sami například s využitím LINQ operátoru Aggregate.
static void Main()
{
PrintSum(new List<int?> { });
PrintSum(new List<int?> { null });
PrintSum(new List<int?> { null, 0, null });
PrintSum(new List<int?> { 1, 2, 3, null, 5, 6 });
}
private static void PrintSum(IEnumerable<int?> source)
{
int? sum = source.Aggregate((int?)null, (s, i) => i == null ? s : s.GetValueOrDefault() + i);
Console.WriteLine(sum == null ? "[null]" : sum.ToString());
}
Nyní bude výstup následující:
[null]
[null]
0
17