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