Laden...

C# 6 - Übersicht der Neuigkeiten

Erstellt von gfoidl vor 9 Jahren Letzter Beitrag vor 9 Jahren 6.738 Views
gfoidl Themenstarter:in
6.911 Beiträge seit 2009
vor 9 Jahren
C# 6 - Übersicht der Neuigkeiten

Hallo zusammen,

das C#-Team hat einen Beitrag über die Neuigkeiten in C# 6 verfasst - siehe New Features in C# 6

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

3.511 Beiträge seit 2005
vor 9 Jahren

Bis auf die "Auto-property initializers", die "Getter-only auto-properties" und die "Expression-bodied function members" alles ganz nett. Aber die genannten finde ich grausam. Bestes Feature: await in try..catch..finally.

"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)

16.828 Beiträge seit 2008
vor 9 Jahren

Ich finde, dass das mit die effizienteste Anpassung von C# überhaupt ist, da viele Alltags-Hindernisse gelöst werden.
Besonders nameof, String interpolation und die Null-conditional operators sowie die Exception-Filter finde ich einfach klasse.

Die Member declaration features sehe ich als hilfreich an, aber nicht als intuitiv.
Sie sind sehr praktisch, aber ich finde die Art und Weise der Änderung in C# als sehr krasse Major-Änderung an - irgendwie zu viel des Guten.
Man merkt hier sehr, dass C# doch in der Web-Welt wichtiger wird und diese Sprach-Konstrukte aus den Web-Script-Sprachen nun hier langsam Einzug finden; finde ich aber nicht unbedingt gut.

Die usings sind für mich auch Käse.

49.485 Beiträge seit 2005
vor 9 Jahren

Hallo zusammen,

ich habe erst jetzt Zeit gefunden, mich mit den Neuerungen zu beschäftigen. Hier meine Eindrücke:

nameof stellt nur sicher, dass es den angegebenen Namen z.B. einer Property gibt, aber nicht, dass es auch die Property ist, die man meinte, insbesondere beim Kopieren von Code für z.B. INotifyPropertyChanged. Da ist es weiterhin besser das CallerMemberName-Attribut zu benutzen, siehe Suche Variable für Filename oder Methode für optionale Argumente (C# 5.0?).

Außerdem frage ich mich, ob man nicht an manchen Stellen den vollqualifizierten Namen haben möchte und nicht nur den letzten Namensbestandteil wie ihn nameof liefert.

In bestimmten Fällen ist nameof aber sicher nett.

~~Lustigerweise bringt die String interpolation genau das Problem mit sich, was im Zusammenhang mit nameof als fehleranfällig beschrieben wird, nämlich Namen und Ausdrücke in String-Literalen. Ok, zugegeben, auch bisher musste der Format-String bestimmte Anforderungen erfüllen, die erst zur Laufzeit geprüft wurden. Trotzdem erhöht sich die Anzahl Fehlermöglichkeiten.

Für (menschliche) Übersetzer sehe ich Vor- und Nachteile. Einerseits muss sich der Übersetzer nicht damit herumschlagen, wofür die Platzhalter 0, 1, 2 usw. stehen, sondern hat einen direkten Bezug. Anderseits darf sich der Übersetzer bei den (möglicherweise komplexen) Ausdrücken nicht verschreiben, sonst gibt es Exceptions zur Laufzeit. Außerdem finde ich die Möglichkeit, dass Übersetzer die Ausdrücke (versehentlich oder absichtlich) ändern können, gefährlich. Übersetzer müssen außerdem aufpassen, dass sie die Namen in den Ausdrücken nicht mitübersetzen. Sie dürfen also aus p.Age nicht p.Alter machen.

Man sollte also genau abwägen, ob man dieses Feature einsetzt oder nicht.~~

[EDIT]Da es sich bei der String interpolation tatsächlich um ein Compilezeit-Feature handelt, wie Th69 weiter unten schreibt, greift die gestrichene Argumentation - die von einem Laufzeit-Feature ausgeht - nicht. Daher ist es ein nettes Feature, gegen das sich nichts sagen lässt, außer dass es einen eher eingeschränkten Einsatzbereich (eben nur String-Literale) hat und damit String.Format nicht überflüssig macht.[/EDIT]

Der Null-conditional operator ist praktisch. Eigentlich sogar so praktisch, dass man überlegen könnte, das Verhalten zum Standard zu machen, wenn das denn nicht ein Beaking Change wäre. In den wenigen Fällen, in denen tatsächlich eine NullReferenceException geworfen werden soll, könnte man die "umgekehrte" Syntax einführen:

int length = customers!.Length;

**
Index initializers** sind ganz nett, nur frage ich mich, warum man dafür eine neue Syntax braucht. Man kann jetzt schon schreiben:

var numbers = new Dictionary<int, string> {
    { 7, "seven"},
    { 9, "nine"},
    {13, "thirteen" }
};

Das ist für meinen Geschmack genau so gut oder schlecht lesbar wie die neue Syntax. Und erfordert pro Zeile (bei üblicher Formatierung ein Leer-)Zeichen weniger, jedenfalls nicht mehr. Die neue Syntax ist also nicht mal kompakter.

Extension Add methods sind nur konsequent und hätten schon von Anfang genauso wie Instanz Add methods behandeln werden sollen. Vermutlich war es nur ein Versehen, dass es bisher nicht ging.

Zur Overload resolution kann ich nicht viel sagen, weil zumindest in dem verlinkten Blog-Beitrag nichts zu den Details steht. Sollte es wirklich so sein, dass die Methodenauswahl jetzt besser den Erwartungen der Programmierer entspricht, bleibt nur die Frage, ob dadurch Breaking Changes entstehen, wenn man bestehenden Code neu kompiliert.

Exception filters sind mir zu magic, und das ohne Not. Erst recht, wenn im Filter - wie vorgeschlagen - eine Methode mit Seiteneffekt, z.B. fürs Logging aufgerufen wird. Die angegebene Begründung für Exception filters, ist, dass der StackTrace sich bei einem re-throw ändert (=abgeschnitten wird). Das stimmt allerdings nicht wirklich. Bei einem echten re-throw catch (Exception) { throw; } bleibt der StackTrace unverändert(*). Ändern würde er sich nur bei catch (Exception e) { throw e; }. Es besteht also gar keine Notwendigkeit für Exception filters. Ich würde davon abraten.

EDIT Es ändert sich lediglich die Zeilennummer, die zu der aktuellen Methode angegeben wird. Diese ist nicht mehr die von dem Methodenaufruf, der mit der Exception zurückkehrt, sondern die von der Zeile mit dem throw (bzw. merkwürdigerweise der mit dem Ende des Blocks, der das throw enthält, bzw. sogar der mit dem ersten Statement nach diesem Block; aber das ist wohl eine andere Geschichte).[/EDIT]

Await in catch and finally blocks ist nur konsquent und hätten schon bei der Einführung von await erlaubt sein sollen.

Auto-property initializers und getter-only auto-properties ist nur konsequent und hätten schon bei der Einführung von Auto-property möglich sein sollen. Gut ist, dass man getter-only auto-properties auch in Konstruktor setzten kann. Insgesamt eine gute Umsetzung.

Bei Expression-bodied function members bin ich mir unschlüssig. Für kurze Methoden und Getter spart es Zeilen und etwas Schreibarbeit. Aber irgendwie kann ich mich damit nicht anfreunden. So viel länger ist

public Point Move(int dx, int dy) { return new Point(x + dx, y + dy); }

statt

public Point Move(int dx, int dy) => new Point(x + dx, y + dy);

nun auch nicht. Und eigentlich sogar etwas lesbarer finde ich. Vielleicht gewöhnlich ich mich daran, aber momentan überwiegt für mich die Lesbarkeit der gewohnten Syntax die Vorteile der geringen Ersparnis. Momentan würde ich davon abraten.

Parameterless constructors in structs gefallen mir auch nicht. Es ist verwirrend, dass ein explizit definierter parameterloser Konstruktor nur in einem bestimmten Fall aufgerufen wird (bei explizitem new auf einen Strukturtyp), aber in anderen nicht (z.B. new auf einem Array von einem Strukturtyp). Ich würde davon abraten.

[EDIT]Parameterless constructors in structs haben es nicht in das finale Release von C# 6.0 geschafft.[/EDIT]

using static ist sicher in bestimmten Fällen (System.Math) ganz nett und praktisch. Verleitet aber möglicherweise dazu, stärker prozedural statt objektorientiert zu arbeiten. Man sollte das Feature bewusst und überlegt einsetzen.

Fazit: Es spricht dafür, wie ausgereift C# schon ist, wenn die Verbesserungen überwiegend kleine Details betreffen und sich teilweise auf reinen syntaktischen Zucker beschränken. Manche Änderungen scheinen mir praktisch und solide, andere etwas unmotiviert oder sogar wenig durchdacht.

herbivore

4.938 Beiträge seit 2008
vor 9 Jahren

Hallo herbivore,

ich kann mich den meisten deiner Argument anschließen.
Bei der String-Interpolation jedoch verstehe ich es so, daß die Ausdrücke direkt schon vom Compiler (wie bei der alten Format-Schreibweise die Parameter) überprüft werden, d.h. es ist wirklich nur "syntactic sugar".

49.485 Beiträge seit 2005
vor 9 Jahren

Hallo Th69,

es freut mich, dass meine Argumente für dich überwiegend stimmig sind.

Format-Strings werden - so wie ich das sehe - momentan nicht vom Compiler geprüft und werden es nach der Einführung des "String interpolation"-Features wohl auch weiterhin nicht. Zumindest steht nichts derartiges in dem Blog-Artikel. In vielen Fällen wäre eine Prüfung der Format-Strings durch den Compiler gar nicht möglich, nämlich immer dann, wenn sie erst zur Laufzeit bekannt sind, z.B. weil sie aus einer Datei, Datenbank oder externen Ressourcen-DLL stammen oder erst zur Laufzeit dynamisch zusammengebaut werden.

herbivore

4.938 Beiträge seit 2008
vor 9 Jahren

Es geht hier aber nicht um den String.Format-Parameter, sondern der Ausdruck


var s = $"{p.Name} is {p.Age} year{{s}} old";

wird anstelle des Aufrufs der String.Format-Methode vom Compiler ausgeführt d.h. der Compiler erzeugt quasi intern daraus den String.Format-Aufruf:


String.Format("{0} is {1} year{{s}} old", p.Name, p.Age);

(so verstehe ich das jedenfalls 😉

Klar wird der eigentliche Format-Parameter erst zur Laufzeit ausgewertet, aber die Parameter dazu sind aber vom Compiler ausgewertete Ausdrücke.

Edit: Man muß für diesen Fall also nicht mehr explizit String.Format aufrufen!
Für externe Format-Strings wird man aber weiterhin die String.Format()-Methode aufrufen müssen und dabei dann weiterhin bei der {0}-Syntax bleiben müssen.
Ob dieses Feature angesichts der Lokalisierung von Anwendungen wirklich nützlich ist, ist also eine andere Sache...

49.485 Beiträge seit 2005
vor 9 Jahren

Hallo Th69,

ok, du könntest recht haben. Wenn die Interpolation ein Compilezeit-Feature ist, dann sieht es natürlich anders aus. Das würde bedeuteten, dass es nur bei String-Literalen direkt im Code greift. Vergleichbar mit der Umsetzung von Escape-Sequenzen durch den Compiler in die zugehörigen entsprechenden Steuerzeichen. Ich habe meinen Beitrag oben entsprechend geändert.

Vermutlich müssten dann auch die Ausdrücke in dem Kontext, in dem das String.Literal im Code steht, existieren bzw. gültig sein. Das heißt, folgender Code müsste funktionieren:


void M () {
   Person p = new Person ();
   String s = $"{p.Name} is {p.Age} year{{s}} old";
}

Aber die folgende Verwendung müsste scheitern:

String fmt = $"{p.Name} is {p.Age} year{{s}} old";
void M () {
   Person p = new Person ();
   String s = fmt;
}

Fraglich ist auch, ob man vor den String const (vermutlich nicht) oder readonly (schon eher) schreiben könnte.

Und das Feature dürfte natürlich erst recht nicht funktionieren, wenn der String in einer Datei oder Datenbank oder einer externen Ressourcen-DLL steht.

herbivore

A
29 Beiträge seit 2012
vor 9 Jahren

Die String-Interpolation habe ich bisher auch als Compiler-Feature verstanden. Finde die Funktion auch ganz nett.

Allerdings sehe ich kaum Vorteile im Vergleich zu SmartFormat.NET, da auch noch einige weitere Features hat.
Klar, man hat eine Prüfung des Format-Strings schon bei der Kompilierung und je nach dem wie es intern umgesetzt wird eventuell eine bessere Performance (string.Format ist ja etwas langsamer als normale String-Verkettung mit dem + Operator. Aber ob das dann am Ende so viel ausmachen wird...?

Das Argument für die Exception-Filters hab ich auch nicht nachvollziehen können. Wie herbivore ja schon gesagt hat, bleibt der StackTrace bei einem einfachen throw ja auch erhalten.

Der Null-condition Operator war meiner Meinung nach auch schon lange überfällig. Sehr nützlich!

Ansonsten war ja auch ein Ziel der neuen C#- und VB.NET-Version, die beiden Sprachen näher aneinanderzurücken. Das using-static-Feature beispielsweise gab es in VB.NET von Anfang an (damals wohl aus der Motivation heraus, VB6-Umsteigern entgegenzukommen).
Sei's drum, nützlich kann dieses Feature trotzdem sein.

16.828 Beiträge seit 2008
vor 9 Jahren

Ihr müsst mal den Fokus von C# mittlerweile anschauen...
Es hat nicht nur die Anwendungsentwicklung im Auge, sondern teilweise sogar das Scripting im Azure Umfeld.

Es konkurriert also nicht nur mit C++ und Java, sondern zB auch in gewisser Weise mit Python, JavaScript und Co - und dort sind solche String-Formattierungen schon lange üblich; Syntax-Zucker wie das Null-Verhalten sowieso.

Gerade Administratoren werden hier also sehr einfach mit der C# Sprache in Kontakt kommen (können).