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:

[csharp]
// 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)) ...
[/csharp]

…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:

[csharp]

<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>

[/csharp]

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:

[csharp]

<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>

[/csharp]

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:

[csharp]
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;
}
}

[/csharp]

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:

[csharp]
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
[/csharp]

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

Další expression-bodied members

[csharp]
// 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";
}
[/csharp]

…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:

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

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>

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

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

[csharp]
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;
[/csharp]

…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