C# uusia ominaisuuksia

C#:n ominaisuudet ovat laajentuneet paljon sen jälkeen, kun tein C#/.NET-sivun. Tässä muutama uudempi ominaisuus mitä ainakin itse olen käyttänyt paljon.

Null-conditional -operaattori (?.)

// Monesti on joutunut tarkistamaan pitkän listan objekteja null-arvojen varalta
var data = GetData(criteria);
if(data != null && data.Items != null)
{
    var item = data.Items.FirstOrDefault(i => i.SomeField == valueToFind);
    if(item != null)
    {
        DoSomethingWithItem(item);
    }
}

// ?. -operaattori vähentää tarvetta null checkeille
// se palauttaa null, jos vasemman puolen arvo on null
// muussa tapauksessa se palauttaa oikealta tulevan arvon
var data = GetData(criteria);
var item = data?.Items?.FirstOrDefault(i => i.SomeField == valueToFind);
if(item != null)
{
    DoSomethingWithItem(item);
}

// kätevä myös EventHandlerien kanssa
public event EventHandler<MyData> DataUpdated;

// EventHandleria kutsutaan vain, jos sillä on kuuntelija
DataUpdated?.Invoke(this, myData);

String interpolation

// kuka jaksaa laskea placeholderien indeksejä?
var text1 = string.Format("{0} {1} {2}", foo, bar(), baz);
// liian vaikealukuinen
var text2 = foo + " " + bar() + " " + baz;

// näinkin voi tehdä
var text3 = $"{foo} {bar()} {baz}";

Tuple

Ennen tupleja yksi C#:n ärsyttävyyksistä oli monen arvon palauttaminen metodista. Piti joko tehdä luokka, johon tiedot keräsi tai vaihtoehtoisesti käyttää out -parametreja.

// Tuplessa määritellään suluissa tietotyypit (ja nimet)
// Nimiä ei ole pakko antaa, mutta se helpottaa, koska muuten ne ovat Item1, Item2 jne.
static (int Number, string Text, DateTime Time) GetTuple()
{
    return (123, "test", DateTime.Now);
}

// ...
var result = GetTuple();
Console.WriteLine($"{result.Number} {result.Text} {result.Time}");

// arvot voi myös purkaa muuttujiin
(int num, string s, DateTime dt) = GetTuple();
Console.WriteLine($"{num} {s} {dt}");

// tai näin
var (num2, s2, dt2) = GetTuple();

Pattern matching

Switchissä voi tarkistaa myös muuttujan tyypin ja tehdä lisävertailuja lisäämällä when -ehdon.

var items = new object[] { 123, 234, "test", DateTime.Today, DateTime.Now.AddHours(1), null };

foreach(var item in items)
{
    switch (item)
    {
        case int i when i % 2 == 0:
            Console.WriteLine("Even number: " + i);
            break;
        case int i: // parilliset numerot tarttuivat jo edelliseen caseen
            Console.WriteLine("Odd number: " + i);
            break;
        case string s:
            Console.WriteLine("Text: " + s);
            break;
        case DateTime dt when dt < DateTime.Now:
            Console.WriteLine("Past DateTime: " + dt);
            break;
        case DateTime dt when dt > DateTime.Now:
            Console.WriteLine("Future DateTime: " + dt);
            break;
        case null:
            Console.WriteLine("Nothing");
            break;
        default:
            break;
    }
}