Od chvíle, kdy se Roslyn stal open-source projektem, jsou vedle jeho repositáře k dispozici, mimo jiné, také shrnutí zasedání C# a VB.NET design týmů. Máte tedy možnost nejen vidět, čím se zrovna zabývají, ale můžete jejich rozhodnutí ovlivňovat Vašimi názory. Tato série článků bude sloužit jako rychlý přehled aktuálního dění v budoucí verzi jazyka C# (zatím označované 6.0).
Pokud preferujete angličtinu a rozhodnutí podpořená delším vysvětlením a protipříklady, originální verze jsou k dispozici na codeplexu Roslynu. Pokud Vám náhodou unikly zatím zveřejněné novinky, můžete si o nich přečíst v mém článku Co přinese C# 6.0.
Indexed members
Tato vlastnost nesklidila zrovna nadšené ohlasy. Pár zastánců si našla, ale většina vývojářů je popuzena tím, že by se syntaxe x.$y dostala do jazyka.
var customer = new JsonData
{
$first = "John", // => ["first"] = "John"
$last = "Doe" // => ["last"] = "Doe"
};
string first = customer.$first; // => customer["first"]
Rozhodnutí týmu? Odebrat.
Null propagating operator
string name = GetCustomer()?.Name;
// namísto
var temp = GetCustomer();
string name = (temp == null) ? null : temp.Name;
postupně dostává finální podobu. Řeší se zejména idiomatika, aktuálně asociativita operátoru, aby bylo pro jednoduché i složité případy na první pohled jasné, co je výsledkem výrazu.
Assignment to getter-only auto-properties
Pro pohodlnější vytváření immutable typů budou sloužit getter-only auto-properties
public string Id { get; }
Pokud chceme toto dnes, musíme udělat následující
private readonly string id;
public string Id { get { return id; } }
a nastavit id v konstruktoru nebo jej inicializovat přímo v deklaraci, což není zdaleka tak pohodlné. V nové verzi je tedy možné takovou property nastavit z primary konstruktoru nebo v deklaraci.
public class Customer(string id)
{
public string Id { get; } = id;
}
// nebo
public string Id { get; } = "Id123";
Občas se ale stane, že se budeme potřebovat vrátit k normálnímu konstruktoru a nastavit tuto property z něj. Rozhodnutí týmu? Getter-only auto-properties bude možné inicializovat i z normálního konstruktoru za cenu mírně odlišného chování. Hodnota se přiřadí do automaticky generovaného privátního backing field (třídní proměnná) dané property. Proč mírně odlišné chování? Protože property se setterem se budou stále nastavovat zavoláním setteru, nikoliv přímým zápisem do backing fieldu.
public class Customer
{
public string Id { get; }
public Customer(string id)
{
Id = id;
}
}
Primary constructor body
Nejvíce otázek ohledně primary konstruktoru bylo okolo jejich těla. Aktuálně nedovolují například validaci argumentů, což je škoda. Vymyslet řešení nebylo složité.
public class Customer(string id)
{
{
if (id == null) throw new ArgumentNullException("id");
}
public string Id { get; } = id;
}
Co ovšem vyvolalo diskuzi je interpretace tohoto bloku. V jaké fázi konstrukce objektu se bude volat? První možnost byla initializer body, který by se volal ještě před voláním do báze, nebyl závislý na primary konstruktoru a mohlo by jich být více. Druhá možnost, constructor body na druhou stranu na primary konstruktoru závislý je, může být jen jeden a volá se až po volání do báze. Jako vítěz vzešla právě druhá možnost, protože je více intuitivní.
Initialization scope
Initialization scope je nový prostor, ve kterém lze přistupovat k parametrům primary konstruktoru. Vznikl zejména proto, aby umožnil vytvoření třídní proměnné pojmenované stejně, jako parametr primary konstruktoru, bez vzniku chyby. To znamená, že pokud Vám nevyhovuje primary constructor field parameter, pak stále můžete využívat třídní proměnné a inicializovat ji z primary konstruktoru.
// automaticky vygeneruje privátní třídní proměnnou pojmenovanou id
// private string id = primary constructor field parameter
public class Customer(private string id)
{
}
// následující teď zatím možné není, ale bude
// je to trochu zavádějící, ale alespoň trochu podobné this.id = id
public class Customer(string id)
{
private string id = id;
}
A co tato novinka umožní? Například následující definici třídy (ukázka z ofic. zdroje).
public class ConfigurationException(Configuration configuration, string message)
: Exception(message)
{
private Configuration configuration = configuration;
public bool IsRemote { get; } = (var settings = configuration.Settings)["remote"];
public bool IsAsync { get; } = settings["async"];
}
Líbí se Vám to? Jste zděšení? Máme možnost se k tomu vyjádřit nejen v komentářích pod tímto článkem, ale hlavně v diskuzi deníku design týmu.