W dzisiejszym artykule skupimy się na opisaniu nowości w języku C# w wersji 6.0. Bez omawiania historii przechodzimy do najnowszej wersji języka, która w poniższych porównaniach zostanie zestawiona ze starszymi wersjami.
W dzisiejszym artykule skupimy się na opisaniu nowości w języku C# w wersji 6.0. Bez omawiania historii przechodzimy do najnowszej wersji języka, która w poniższych porównaniach zostanie zestawiona ze starszymi wersjami.
Wszyscy jesteśmy dobrze zaznajomieni z pojęciem statycznego członka klasy. Najprosty przykład to wywołanie metody WriteLine(...) z klasy Console. Od wersji 6.0 nie musimy tego robić w znany wszystkim sposób. Możemy zaimportować statyczny typ.
Przed C# 6.0:
using System; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Console.WriteLine("Witaj Drogi Czytelniku!"); } } }
C# 6.0:
using System; using static System.Console; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { WriteLine("Witaj Drogi Czytelniku!"); } } }
Możecie zapomnieć o formatowaniu łańuchów tekstowych z klamrami {0}, aby następnie zamienić je na rzeczywiste wartości. C# 6.0 ma nową funkcję pod nazwą interpolacji ciągu (string interpolation) dzięki której można teraz bezpośrednio zapisywać swoje argumenty w formatowanym ciągu.
Przed C# 6.0:
using System; using static System.Console; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string car = "Audi"; string model = "RS6 C7"; WriteLine("Sportowe kombi z rodziny {0} to model {1}.", car, model); ReadKey(); } } }
C# 6.0:
using System; using static System.Console; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string car = "Audi"; string model = "RS6 C7"; WriteLine($"Sportowe kombi z rodziny {car} to model {model}."); ReadKey(); } } }
W tak formatowanym tekście można nawet wprowadzić instrukcje warunkowe:
using System; using static System.Console; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string car = "Audi"; string model = "RS6 C7"; int priceFrom = 539000; WriteLine($"Sportowe kombi z rodziny {car} to model {model}."); WriteLine($"Wartość: {(priceFrom > 100000 ? "drogie autko" : "tanie auto")}"); ReadKey(); } } }
Nowa wersja języka zmienia podejście do inicjowania słowników. W poprzednich wersjach proces ten odbywa się na zasadzie deklaracji pary {"klucz", "wartość"}. W obecnej wersji klucz może być umieszczony w nawiasach kwadratowych ["Klucz"] a następnie możemy do niego przypiasać wartość: ["Klucz"] = wartość;. Nowa składnia jest bardziej czytelna i przejrzysta.
Przed C# 6.0:
using System; using System.Collections.Generic; using static System.Console; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Dictionary<int, string> data; data = new Dictionary<int, string>() { {1, "Audi" }, {2, "Porsche"}, {3, "Maserati" } }; foreach (var item in data) { WriteLine(item.Key + " : " + item.Value); } ReadKey(); } } }
C# 6.0:
using System; using System.Collections.Generic; using static System.Console; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Dictionary<int, string> data; data = new Dictionary<int, string>() { [1] = "Audi", [2] = "Porsche", [3] = "Maserati" }; foreach (var item in data) { WriteLine($"{item.Key} : {item.Value}"); } ReadKey(); } } }
C# 6.0 pokazuje nową koncepcję inicjowania właściwości – zamiast wykonywania tego procesu w konstuktorze. Kolejną wartą uwagi nowością jest możliwość zadeklarowania samego gettera - dzięki temu setter zostanie ustawiony jako prywatny i użytkownik nie będzie miał do niego dostępu.
Przed C# 6.0:
using System; using System.Collections.Generic; using static System.Console; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { CarClass car = new CarClass(); WriteLine("Marka: {0}, Model: {1}", car.Brand, car.Model); ReadKey(); } } class CarClass { public string Brand { get; set; } public string Model { get; set; } public CarClass() { Brand = "Audi"; Model = "RS6 C7"; } } }
C# 6.0:
using System; using System.Collections.Generic; using static System.Console; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { CarClass car = new CarClass(); WriteLine($"Marka: {car.Brand}, Model: {car.Model}"); ReadKey(); } } class CarClass { public string Brand { get; } = "Audi"; public string Model { get; set; } = "RS6 C7"; } }
Wyrażenie to przychodzi nam z pomocą, gdy zaczynamy myśleć o refractoringu naszego kodu. Wyobraźmy sobie sytuację w której sprawdzamy wartość jakiegoś parametru a następnie wyświetlamy błąd związany z tym parametrem – hardcoded string. Jeżeli teraz zmienimy nazwę naszego parametru nie wpłynie to nasz komunikat błędu.
Przed C# 6.0:
using System; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { DoSomething(); } private static void DoSomething() { int? x = null; if(x==null) { // x jest nazwą typu. Co jeżeli ktoś zmieni nazwę? // Komunikat błędu będzie nieodpowiedni. throw new Exception("x is null"); } } } }
C# 6.0:
using System; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { DoSomething(); } private static void DoSomething() { int? number = null; if(number==null) { throw new Exception(nameof(number) + " is null"); } } } }
W nowej wersji języka C# pojawia się nowa konepcja operatowa warunkowego null, która pozowala sprawdzić czy instacja obiektu jest pusta czy też nie bez wprowadzania instrukcji warunkowej. Składania wyrażenia nie jest skomplikowana - ?. wyrażenie pozwala na sprawdzenie czy instacja jest pusta czy nie, jeżeli nie wykonywany jest kod tego wyrażenia, w przeciwnym wypadku wykonywany jest kod po wyrażeniu ??. Spójrz na poniższe przykłady.
Przed C# 6.0:
using System; using System.Threading.Tasks; using static System.Console; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Car car = new Car(); if(car.Brand==String.Empty) { car = null; } // sprawdzenie po staramu WriteLine(car != null ? car.Brand : "Brak definicji"); ReadKey(); } } public class Car { public string Brand { get; set; } = ""; } }
C# 6.0:
using System; using System.Threading.Tasks; using static System.Console; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Car car = new Car(); if(car.Brand==String.Empty) { car = null; } // nowy operator null // jeżeli wyrażenie jest prawdziwe zostanie wykonany blok kodu po lewej stronie // jeżeli nie - blok kodu po prawej stronie WriteLine(car?.Brand ?? "Brak definicji"); ReadKey(); } } public class Car { public string Brand { get; set; } = ""; } }
Bardzo dużym udogodnieniem jest możliwość pisania metod i właściwości bez ich caiała. W takim wypadku należy użyć wyrażenia lambda i można przystąpić do pisania właściwego kodu.
C# 6.0 (metoda):
using static System.Console; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { double x = 32.21; double y = 54.32; WriteLine(AddNumber(x, y)); ReadKey(); } static double AddNumber(double x, double y) => x + y; } }
C# 6.0 (właściwość)
using static System.Console; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Car car = new Car(); WriteLine(car.FullName); ReadKey(); } } public class Car { public string Brand { get; } = "Audi"; public string Model { get; } = "RS6"; public string FullName => Brand + " " + Model; } }