C# 7.0 – Rychlý přehled novinek
Se svolením autora převzato z HAVIT Knowledge Base:
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<int> numbers)
{
intmin = int.MaxValue;
intmax = int.MinValue;
foreach(varn innumbers)
{
min = (n < min) ? n : min; max = (n > 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 => IsActive(i));
if(!rawData.Any())
{
returnmyClassDataService.GetSecondaryItems().Where(i => IsActive(i));
}
returnrawData;
boolIsActive(MyClass item)
{
return(item.State == States.Active) && (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