LINQ: Operátor Sum a hodnoty null

Tomáš Holan       20. 5. 2013       LINQ       9056 zobrazení

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:

  1. Výsledkem operace Sum pro prázdnou sekvenci je hodnota nula.
  2. 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

 

hodnocení článku

0       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback