C# 7.0 – Rychlý přehled novinek


Se svolením autora převzato z HAVIT Knowledge BaseHAVIT


Out variables

Možnost deklarovat out-proměnné inline při volání metod:

// dříve
int x;
if (int.TryParse(s, out x)) ...

// C# 7.0
if (int.TryParse(s, out int x)) ...

// C# 7.0
if (int.TryParse(s, out var x)) ...

…rozhodně přehlednější zápis.

Tuples

Možnost vytvářet lehké datové struktury s několika fieldy a používat je i jako návratové hodnoty metod:



<pre class="brush: csharp">private static(intMax, intMin) Range(IEnumerable&lt;int&gt; numbers)
{
    intmin = int.MaxValue;
    intmax = int.MinValue;
    foreach(varn innumbers)
    {
        min = (n &lt; min) ? n : min; max = (n &gt; max) ? n : max;
    }
    return(max, min);
}

varresult = Range(numbers);
Console.Write($"{result.Min} - {result.Max}");

(intmax, intmin) = Range(numbers); // deconstruction
</pre>

Bude zneužíváno lenochy, co nechtějí psát malé ViewModely, ale budou raději riskovat zmatky při deconstruction (záleží na pořadí prvků, ne názvech!).

Lokální funkce

Možnost definovat pomocné lokální funkce uvnitř metod:



<pre class="brush: csharp">public IEnumerable GetActiveItems()
{
    varrawData = myClassDataService.GetPrimaryItems().Where(i =&gt; IsActive(i));
    if(!rawData.Any())
    {
        returnmyClassDataService.GetSecondaryItems().Where(i =&gt; IsActive(i));
    }
    returnrawData;

    boolIsActive(MyClass item)
    {
        return(item.State == States.Active) &amp;&amp; (item.Rows.Any());
    }
}
</pre>

Dosud bylo možné použít anonymní lambda výrazy, syntaxe je však nyní trochu přívětivější. Zde například chci 2x vyhodnotit stejnou podmínku IsActive, ale z jiné metody ve třídě to nepotřebuji a lokální funkce je tak pro mě přehlednější, než samostatná privátní metoda.

Pattern matching

Možnost pomocí klíčových slov is a switch řídit větvení kódu, popř. s možností dodatečných podmínek when:

public static int SumTree(IEnumerable<object> values)
{
    var sum = 0;
    foreach(var item in values)
    {
        if (item is int val)
            sum += val; // leaf-node
        else if (item is IEnumerable<object> subList)
            sum += SumTree(subList);
    }
    return sum;
}
public static void SwitchPattern(object o)
{
    switch (o)
    {
        case null:
            Console.WriteLine("pattern pro konstantu");
            break;
        case int i:
            Console.WriteLine("Je to číslo!");
            break;
        case Person p when p.FirstName.StartsWith("Ka"):
            Console.WriteLine($"Jméno začíná na Ka: {p.FirstName}");
            break;
        case Person p:
            Console.WriteLine($"Jiné jméno: {p.FirstName}");
            break;
        case var x:
            Console.WriteLine($"jiný typ: {x?.GetType().Name} ");
            break;
        default:
            break;
    }
}

Je to podobné, jako C# 6 přišel s podmínkami u catch-bloků. Při if-is testech na typ se bude hodit.

Ref locals and returns

Možnost použít referenci na proměnnou definovanou jinde:

public ref int Find(int number, int[] numbers)
{
    for (int i = 0; i < numbers.Length; i++)
    {
        if (numbers[i] == number) 
        {
            return ref numbers[i]; // vrať referenci, nikoliv hodnotu
        }
    }
    throw new IndexOutOfRangeException($"{nameof(number)} nenalezeno");
}
 
int[] array = { 1, 15, -39, 0, 7, 14, -12 };
ref int place = ref Find(7, array); // vrátí referenci na pozici se sedmičkou
place = 9; // nahradí v poli nalezenou sedimičku devítkou
WriteLine(array[4]); // vypíše 9

Využití je celkem specifické, ale výjimečně se může hodit.

Další expression-bodied members

// Expression-bodied constructor
public ExpressionMembersExample(string label) => this.Label = label;
 
// Expression-bodied finalizer
~ExpressionMembersExample() => Console.Error.WriteLine("Finalized!");
 
private string label;
 
// Expression-bodied get / set accessors.
public string Label
{
    get => label;
    set => this.label = value ?? "Default label";
}

…snad jedině u jednoduchých properties to zlepšuje čitelnost, jinak nejsem moc velkým příznivcem expression-bodies members.

Vyhazování výjimek z výrazů

Hodí se třeba v kombinaci s exression-bodied members:

public string Name
{
    get => name;
    set => name = value ?? throw new ArgumentNullException();
}

ValueTask pro async

Task<T> je referenční datový typ a jeho použití znamená alokaci objektu na haldě. Pro hodnotové návratové typy nově přichází optimalizace v podobě ValueTask<T>

public async ValueTask<int> Func()
{
    await Task.Delay(100);
    return 5;
}

Čitelnější možnosti zápisu číselných konstant

public const int One =  0b0001; // binární číslo
public const int Sixteen =   0b0001_0000; // oddělovač (lze použít kdekoliv, ignoruje se)
public const long HodneMoc = 100_000_000_000;
public const double AvogadroConstant = 6.022_140_857_747_474e23;

…binární zápis se může hodit na flagy, oddělovač na velká čísla.


Se svolením autora převzato z HAVIT Knowledge Base


Další informace v angličtině najdete v novějším článku https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/
M
áte-li chuť prozkoumat hlouběji co se v oblasti C# připravuje, případně podiskutovat s tvůrci, keouněte sem: https://github.com/dotnet/csharplang


 

Comments (0)

Skip to main content